Compare commits
No commits in common. "87e9fb36e168d31eec7b0cf1bc50a28c74cdce0a" and "78c93f3c2004713465b19fcfd361daebced12980" have entirely different histories.
87e9fb36e1
...
78c93f3c20
File diff suppressed because it is too large
Load Diff
21
Cargo.toml
21
Cargo.toml
|
@ -30,33 +30,31 @@ async-stream = "0.3"
|
||||||
axum = "0.7"
|
axum = "0.7"
|
||||||
axum-extra = "0.9"
|
axum-extra = "0.9"
|
||||||
base64 = "0.22"
|
base64 = "0.22"
|
||||||
cached = "0.53"
|
cached = "0.47"
|
||||||
cfg-if = "1"
|
cfg-if = "1"
|
||||||
chrono = "0.4"
|
chrono = "0.4"
|
||||||
compact_str = "0.8"
|
compact_str = "0.7"
|
||||||
dotenvy = "0.15"
|
dotenvy = "0.15"
|
||||||
ed25519-dalek = "2.1"
|
ed25519-dalek = "2.1"
|
||||||
either = "1.9"
|
either = "1.9"
|
||||||
emojis = "0.6"
|
emojis = "0.6"
|
||||||
futures = "0.3"
|
futures = "0.3"
|
||||||
futures-channel = "0.3"
|
|
||||||
futures-core = "0.3"
|
futures-core = "0.3"
|
||||||
futures-util = "0.3"
|
futures-util = "0.3"
|
||||||
headers = "0.4"
|
headers = "0.4"
|
||||||
http = "1.0"
|
http = "1.0"
|
||||||
httpdate = "1"
|
httpdate = "1"
|
||||||
hyper = "1.1"
|
hyper = "1.1"
|
||||||
idna = "1"
|
idna = "0.5"
|
||||||
indexmap = "2.2"
|
indexmap = "2.2"
|
||||||
itertools = "0.13"
|
itertools = "0.12"
|
||||||
lru = "0.12"
|
lru = "0.12"
|
||||||
miette = "7"
|
miette = "5.9"
|
||||||
nom = "7"
|
nom = "7"
|
||||||
nom_locate = "4"
|
nom_locate = "4"
|
||||||
percent-encoding = "2.2"
|
percent-encoding = "2.2"
|
||||||
priority-queue = "2.0"
|
quick-xml = "0.31"
|
||||||
quick-xml = "0.36"
|
redis = "0.24"
|
||||||
redis = "0.26"
|
|
||||||
regex = "1.9"
|
regex = "1.9"
|
||||||
rsa = "0.9"
|
rsa = "0.9"
|
||||||
reqwest = "0.12"
|
reqwest = "0.12"
|
||||||
|
@ -66,15 +64,14 @@ serde = "1"
|
||||||
serde_json = "1"
|
serde_json = "1"
|
||||||
serde_urlencoded = "0.7"
|
serde_urlencoded = "0.7"
|
||||||
sha2 = "0.10"
|
sha2 = "0.10"
|
||||||
smallvec = "1.13"
|
strum = "0.25"
|
||||||
strum = "0.26"
|
|
||||||
tera = { version = "1", default-features = false }
|
tera = { version = "1", default-features = false }
|
||||||
thiserror = "1"
|
thiserror = "1"
|
||||||
tokio = "1.24"
|
tokio = "1.24"
|
||||||
tokio-util = "0.7"
|
tokio-util = "0.7"
|
||||||
tokio-stream = "0.1"
|
tokio-stream = "0.1"
|
||||||
toml = "0.8"
|
toml = "0.8"
|
||||||
tower = "0.5"
|
tower = "0.4"
|
||||||
tower-http = "0.5"
|
tower-http = "0.5"
|
||||||
tracing = "0.1"
|
tracing = "0.1"
|
||||||
tracing-subscriber = "0.3"
|
tracing-subscriber = "0.3"
|
||||||
|
|
|
@ -1,12 +1,16 @@
|
||||||
pub mod data;
|
pub mod data;
|
||||||
|
|
||||||
|
use ext_model_migration::SelectStatement;
|
||||||
|
use sea_orm::sea_query::{Asterisk, Expr, IntoIden, Query, SelectExpr, SimpleExpr};
|
||||||
|
use sea_orm::{
|
||||||
|
Condition, EntityTrait, Iden, JoinType, QueryFilter, QueryOrder, QuerySelect, QueryTrait,
|
||||||
|
Select,
|
||||||
|
};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
use ck::{note, note_reaction, user_note_pining};
|
use ck::{note, note_reaction, user_note_pining};
|
||||||
use data::{sub_interaction_reaction, sub_interaction_renote, NoteData};
|
use data::{sub_interaction_reaction, sub_interaction_renote, NoteData};
|
||||||
use ext_model_migration::SelectStatement;
|
|
||||||
use magnetar_sdk::types::SpanFilter;
|
use magnetar_sdk::types::SpanFilter;
|
||||||
use sea_orm::sea_query::{Asterisk, Expr, IntoIden, Query, SelectExpr, SimpleExpr};
|
|
||||||
use sea_orm::{Condition, EntityTrait, Iden, JoinType, Order, QueryFilter, QuerySelect, QueryTrait, Select};
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use crate::model_ext::{
|
use crate::model_ext::{
|
||||||
join_columns_default, AliasColumnExt, AliasSourceExt, AliasSuffixExt, CursorPaginationExt,
|
join_columns_default, AliasColumnExt, AliasSourceExt, AliasSuffixExt, CursorPaginationExt,
|
||||||
|
@ -15,9 +19,10 @@ use crate::model_ext::{
|
||||||
use crate::user_model::{UserResolveOptions, UserResolver};
|
use crate::user_model::{UserResolveOptions, UserResolver};
|
||||||
use crate::{CalckeyDbError, CalckeyModel};
|
use crate::{CalckeyDbError, CalckeyModel};
|
||||||
|
|
||||||
const INTERACTION_REACTION: &str = "iact.rct.";
|
const PIN: &str = "pin.";
|
||||||
const INTERACTION_RENOTE: &str = "iact.rnt.";
|
const INTERACTION_REACTION: &str = "interaction.reaction.";
|
||||||
const USER: &str = "u.";
|
const INTERACTION_RENOTE: &str = "interaction.renote.";
|
||||||
|
const USER: &str = "user.";
|
||||||
const REPLY: &str = "reply.";
|
const REPLY: &str = "reply.";
|
||||||
const RENOTE: &str = "renote.";
|
const RENOTE: &str = "renote.";
|
||||||
|
|
||||||
|
@ -31,50 +36,16 @@ pub trait NoteVisibilityFilterFactory: Send + Sync {
|
||||||
fn with_note_and_user_tables(&self, note: &dyn Iden) -> SimpleExpr;
|
fn with_note_and_user_tables(&self, note: &dyn Iden) -> SimpleExpr;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub enum NoteResolveMode {
|
|
||||||
Single(String),
|
|
||||||
Multiple(Vec<String>),
|
|
||||||
PinsFromUserId(String),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl NoteResolveMode {
|
|
||||||
fn as_expr(&self) -> SimpleExpr {
|
|
||||||
let id_col = note::Entity.base_prefix().col(note::Column::Id);
|
|
||||||
|
|
||||||
match self {
|
|
||||||
NoteResolveMode::Single(id) => id_col.eq(id),
|
|
||||||
NoteResolveMode::Multiple(ids) => id_col.is_in(ids),
|
|
||||||
NoteResolveMode::PinsFromUserId(user_id) => {
|
|
||||||
let sub_query = Query::select()
|
|
||||||
.expr(SelectExpr {
|
|
||||||
expr: Expr::col(user_note_pining::Column::NoteId).into(),
|
|
||||||
alias: None,
|
|
||||||
window: None,
|
|
||||||
})
|
|
||||||
.from(user_note_pining::Entity)
|
|
||||||
.and_where(Expr::col(note_reaction::Column::UserId).eq(user_id))
|
|
||||||
.order_by_columns([
|
|
||||||
(user_note_pining::Column::CreatedAt, Order::Desc),
|
|
||||||
(user_note_pining::Column::Id, Order::Desc)
|
|
||||||
])
|
|
||||||
.take();
|
|
||||||
|
|
||||||
id_col.in_subquery(sub_query)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct NoteResolveOptions {
|
pub struct NoteResolveOptions {
|
||||||
pub mode: Option<NoteResolveMode>,
|
pub ids: Option<Vec<String>>,
|
||||||
pub visibility_filter: Arc<dyn NoteVisibilityFilterFactory>,
|
pub visibility_filter: Arc<dyn NoteVisibilityFilterFactory>,
|
||||||
pub time_range: Option<SpanFilter>,
|
pub time_range: Option<SpanFilter>,
|
||||||
pub limit: Option<u64>,
|
pub limit: Option<u64>,
|
||||||
pub with_reply_target: bool,
|
pub with_reply_target: bool,
|
||||||
pub with_renote_target: bool,
|
pub with_renote_target: bool,
|
||||||
pub with_interactions_from: Option<String>, // User ID
|
pub with_interactions_from: Option<String>, // User ID
|
||||||
|
pub only_pins_from: Option<String>, // User ID
|
||||||
pub user_options: UserResolveOptions,
|
pub user_options: UserResolveOptions,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -146,6 +117,16 @@ impl SelectNoteInteractionsExt for SelectStatement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn ids_into_expr(ids: &Vec<String>) -> SimpleExpr {
|
||||||
|
let id_col = note::Entity.base_prefix().col(note::Column::Id);
|
||||||
|
|
||||||
|
if ids.len() == 1 {
|
||||||
|
id_col.eq(&ids[0])
|
||||||
|
} else {
|
||||||
|
id_col.is_in(ids)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl NoteResolver {
|
impl NoteResolver {
|
||||||
pub fn new(db: CalckeyModel, user_resolver: UserResolver) -> Self {
|
pub fn new(db: CalckeyModel, user_resolver: UserResolver) -> Self {
|
||||||
NoteResolver { db, user_resolver }
|
NoteResolver { db, user_resolver }
|
||||||
|
@ -160,7 +141,7 @@ impl NoteResolver {
|
||||||
.visibility_filter
|
.visibility_filter
|
||||||
.with_note_and_user_tables(¬e::Entity.base_prefix());
|
.with_note_and_user_tables(¬e::Entity.base_prefix());
|
||||||
|
|
||||||
let id_filter = options.mode.as_ref().map(NoteResolveMode::as_expr);
|
let id_filter = options.ids.as_ref().map(ids_into_expr);
|
||||||
|
|
||||||
let note = select
|
let note = select
|
||||||
.filter(visibility_filter)
|
.filter(visibility_filter)
|
||||||
|
@ -180,11 +161,17 @@ impl NoteResolver {
|
||||||
let visibility_filter = options
|
let visibility_filter = options
|
||||||
.visibility_filter
|
.visibility_filter
|
||||||
.with_note_and_user_tables(¬e::Entity.base_prefix());
|
.with_note_and_user_tables(¬e::Entity.base_prefix());
|
||||||
let id_filter = options.mode.as_ref().map(NoteResolveMode::as_expr);
|
let id_filter = options.ids.as_ref().map(ids_into_expr);
|
||||||
|
|
||||||
let notes_select = select
|
let notes_select = select
|
||||||
.filter(visibility_filter)
|
.filter(visibility_filter)
|
||||||
.apply_if(id_filter, Select::<note::Entity>::filter);
|
.apply_if(id_filter, Select::<note::Entity>::filter)
|
||||||
|
.apply_if(options.only_pins_from.as_deref(), |s, _| {
|
||||||
|
s.order_by_desc(Expr::col((
|
||||||
|
note::Entity.base_prefix().into_iden().join_str(PIN),
|
||||||
|
user_note_pining::Column::CreatedAt,
|
||||||
|
)))
|
||||||
|
});
|
||||||
|
|
||||||
let notes = if let Some(pagination) = &options.time_range {
|
let notes = if let Some(pagination) = &options.time_range {
|
||||||
notes_select
|
notes_select
|
||||||
|
@ -317,6 +304,16 @@ impl NoteResolver {
|
||||||
let mut select = Query::select();
|
let mut select = Query::select();
|
||||||
select.from_as(note::Entity, note_tbl.clone().into_iden());
|
select.from_as(note::Entity, note_tbl.clone().into_iden());
|
||||||
|
|
||||||
|
if let Some(pins_user) = &options.only_pins_from {
|
||||||
|
select
|
||||||
|
.join_columns(
|
||||||
|
JoinType::InnerJoin,
|
||||||
|
note::Relation::UserNotePining.with_from_alias(¬e_tbl),
|
||||||
|
¬e_tbl.join_str(PIN),
|
||||||
|
)
|
||||||
|
.and_where(note_tbl.col(user_note_pining::Column::UserId).eq(pins_user));
|
||||||
|
}
|
||||||
|
|
||||||
self.attach_note(
|
self.attach_note(
|
||||||
&mut select,
|
&mut select,
|
||||||
¬e_tbl,
|
¬e_tbl,
|
||||||
|
|
|
@ -18,4 +18,4 @@ serde = { workspace = true, features = ["derive"] }
|
||||||
strum = { workspace = true, features = ["derive"] }
|
strum = { workspace = true, features = ["derive"] }
|
||||||
tracing = { workspace = true }
|
tracing = { workspace = true }
|
||||||
unicode-segmentation = { workspace = true }
|
unicode-segmentation = { workspace = true }
|
||||||
quick-xml = { workspace = true, optional = true, features = ["serialize"] }
|
quick-xml = { workspace = "true", optional = true, features = ["serialize"] }
|
||||||
|
|
|
@ -5,6 +5,7 @@ use std::marker::PhantomData;
|
||||||
|
|
||||||
use compact_str::{CompactString, ToCompactString};
|
use compact_str::{CompactString, ToCompactString};
|
||||||
use either::Either;
|
use either::Either;
|
||||||
|
use nom::{IResult, Offset, Parser, Slice};
|
||||||
use nom::branch::alt;
|
use nom::branch::alt;
|
||||||
use nom::bytes::complete::{tag, tag_no_case};
|
use nom::bytes::complete::{tag, tag_no_case};
|
||||||
use nom::character::complete::{
|
use nom::character::complete::{
|
||||||
|
@ -15,7 +16,6 @@ use nom::combinator::{eof, fail, map, not, opt, peek, recognize};
|
||||||
use nom::error::ErrorKind;
|
use nom::error::ErrorKind;
|
||||||
use nom::multi::{many0_count, many1, many1_count, many_till, separated_list1};
|
use nom::multi::{many0_count, many1, many1_count, many_till, separated_list1};
|
||||||
use nom::sequence::tuple;
|
use nom::sequence::tuple;
|
||||||
use nom::{IResult, Offset, Parser, Slice};
|
|
||||||
use nom_locate::LocatedSpan;
|
use nom_locate::LocatedSpan;
|
||||||
use quick_xml::events::{BytesText, Event};
|
use quick_xml::events::{BytesText, Event};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
@ -56,6 +56,7 @@ pub enum Token {
|
||||||
Sequence(Vec<Token>),
|
Sequence(Vec<Token>),
|
||||||
Quote(Box<Token>),
|
Quote(Box<Token>),
|
||||||
Small(Box<Token>),
|
Small(Box<Token>),
|
||||||
|
BoldItalic(Box<Token>),
|
||||||
Bold(Box<Token>),
|
Bold(Box<Token>),
|
||||||
Italic(Box<Token>),
|
Italic(Box<Token>),
|
||||||
Center(Box<Token>),
|
Center(Box<Token>),
|
||||||
|
@ -100,6 +101,7 @@ impl Token {
|
||||||
Token::Sequence(tokens) => tokens.first().and_then(Token::str_content_left),
|
Token::Sequence(tokens) => tokens.first().and_then(Token::str_content_left),
|
||||||
Token::Quote(inner) => inner.str_content_left(),
|
Token::Quote(inner) => inner.str_content_left(),
|
||||||
Token::Small(inner) => inner.str_content_left(),
|
Token::Small(inner) => inner.str_content_left(),
|
||||||
|
Token::BoldItalic(inner) => inner.str_content_left(),
|
||||||
Token::Bold(inner) => inner.str_content_left(),
|
Token::Bold(inner) => inner.str_content_left(),
|
||||||
Token::Italic(inner) => inner.str_content_left(),
|
Token::Italic(inner) => inner.str_content_left(),
|
||||||
Token::Center(inner) => inner.str_content_left(),
|
Token::Center(inner) => inner.str_content_left(),
|
||||||
|
@ -122,6 +124,7 @@ impl Token {
|
||||||
Token::Sequence(tokens) => tokens.last().and_then(Token::str_content_right),
|
Token::Sequence(tokens) => tokens.last().and_then(Token::str_content_right),
|
||||||
Token::Quote(inner) => inner.str_content_right(),
|
Token::Quote(inner) => inner.str_content_right(),
|
||||||
Token::Small(inner) => inner.str_content_right(),
|
Token::Small(inner) => inner.str_content_right(),
|
||||||
|
Token::BoldItalic(inner) => inner.str_content_right(),
|
||||||
Token::Bold(inner) => inner.str_content_right(),
|
Token::Bold(inner) => inner.str_content_right(),
|
||||||
Token::Italic(inner) => inner.str_content_right(),
|
Token::Italic(inner) => inner.str_content_right(),
|
||||||
Token::Center(inner) => inner.str_content_right(),
|
Token::Center(inner) => inner.str_content_right(),
|
||||||
|
@ -144,6 +147,7 @@ impl Token {
|
||||||
sequence @ Token::Sequence(_) => sequence.clone(),
|
sequence @ Token::Sequence(_) => sequence.clone(),
|
||||||
Token::Quote(inner) => inner.inner(),
|
Token::Quote(inner) => inner.inner(),
|
||||||
Token::Small(inner) => inner.inner(),
|
Token::Small(inner) => inner.inner(),
|
||||||
|
Token::BoldItalic(inner) => inner.inner(),
|
||||||
Token::Bold(inner) => inner.inner(),
|
Token::Bold(inner) => inner.inner(),
|
||||||
Token::Italic(inner) => inner.inner(),
|
Token::Italic(inner) => inner.inner(),
|
||||||
Token::Center(inner) => inner.inner(),
|
Token::Center(inner) => inner.inner(),
|
||||||
|
@ -209,6 +213,7 @@ impl Token {
|
||||||
}
|
}
|
||||||
Token::Quote(inner) => Token::Quote(Box::new(inner.merged())),
|
Token::Quote(inner) => Token::Quote(Box::new(inner.merged())),
|
||||||
Token::Small(inner) => Token::Small(Box::new(inner.merged())),
|
Token::Small(inner) => Token::Small(Box::new(inner.merged())),
|
||||||
|
Token::BoldItalic(inner) => Token::BoldItalic(Box::new(inner.merged())),
|
||||||
Token::Bold(inner) => Token::Bold(Box::new(inner.merged())),
|
Token::Bold(inner) => Token::Bold(Box::new(inner.merged())),
|
||||||
Token::Italic(inner) => Token::Italic(Box::new(inner.merged())),
|
Token::Italic(inner) => Token::Italic(Box::new(inner.merged())),
|
||||||
Token::Center(inner) => Token::Center(Box::new(inner.merged())),
|
Token::Center(inner) => Token::Center(Box::new(inner.merged())),
|
||||||
|
@ -242,6 +247,7 @@ impl Token {
|
||||||
}
|
}
|
||||||
Token::Quote(inner)
|
Token::Quote(inner)
|
||||||
| Token::Small(inner)
|
| Token::Small(inner)
|
||||||
|
| Token::BoldItalic(inner)
|
||||||
| Token::Bold(inner)
|
| Token::Bold(inner)
|
||||||
| Token::Italic(inner)
|
| Token::Italic(inner)
|
||||||
| Token::Center(inner)
|
| Token::Center(inner)
|
||||||
|
@ -260,6 +266,7 @@ impl Token {
|
||||||
.for_each(|tok| tok.walk_speech_transform(func));
|
.for_each(|tok| tok.walk_speech_transform(func));
|
||||||
}
|
}
|
||||||
Token::Small(inner)
|
Token::Small(inner)
|
||||||
|
| Token::BoldItalic(inner)
|
||||||
| Token::Bold(inner)
|
| Token::Bold(inner)
|
||||||
| Token::Italic(inner)
|
| Token::Italic(inner)
|
||||||
| Token::Center(inner)
|
| Token::Center(inner)
|
||||||
|
@ -288,6 +295,16 @@ impl Token {
|
||||||
.create_element("small")
|
.create_element("small")
|
||||||
.write_inner_content(|w| inner.write(w))?;
|
.write_inner_content(|w| inner.write(w))?;
|
||||||
}
|
}
|
||||||
|
Token::BoldItalic(inner) => {
|
||||||
|
writer
|
||||||
|
.create_element("b")
|
||||||
|
.write_inner_content::<_, quick_xml::Error>(|w| {
|
||||||
|
w.create_element("i")
|
||||||
|
.write_inner_content(|w| inner.write(w))?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
})?;
|
||||||
|
}
|
||||||
Token::Bold(inner) => {
|
Token::Bold(inner) => {
|
||||||
writer
|
writer
|
||||||
.create_element("b")
|
.create_element("b")
|
||||||
|
@ -775,6 +792,8 @@ impl Context {
|
||||||
|
|
||||||
fn base_bold_italic<'a>(&self, input: Span<'a>) -> IResult<Span<'a>, Token> {
|
fn base_bold_italic<'a>(&self, input: Span<'a>) -> IResult<Span<'a>, Token> {
|
||||||
alt((
|
alt((
|
||||||
|
self.partial(Self::tag_bold_italic_asterisk),
|
||||||
|
self.partial(Self::tag_bold_italic_underscore),
|
||||||
self.partial(Self::tag_bold_asterisk),
|
self.partial(Self::tag_bold_asterisk),
|
||||||
self.partial(Self::tag_italic_asterisk),
|
self.partial(Self::tag_italic_asterisk),
|
||||||
self.partial(Self::tag_bold_underscore),
|
self.partial(Self::tag_bold_underscore),
|
||||||
|
@ -1014,7 +1033,7 @@ impl Context {
|
||||||
escape: bool,
|
escape: bool,
|
||||||
matcher: Matcher<'a, 'b, T>,
|
matcher: Matcher<'a, 'b, T>,
|
||||||
fallback: Matcher<'a, 'b, S>,
|
fallback: Matcher<'a, 'b, S>,
|
||||||
) -> impl Fn(Span<'b>) -> IResult<Span<'b>, Token> + 'a
|
) -> impl Fn(Span<'b>) -> IResult<Span<'b>, Token> + '_
|
||||||
where
|
where
|
||||||
FOpen: Fn(Span<'b>) -> IResult<Span<'b>, Span<'b>> + 'a,
|
FOpen: Fn(Span<'b>) -> IResult<Span<'b>, Span<'b>> + 'a,
|
||||||
FClose: Fn(Span<'b>) -> IResult<Span<'b>, Span<'b>> + 'a,
|
FClose: Fn(Span<'b>) -> IResult<Span<'b>, Span<'b>> + 'a,
|
||||||
|
@ -1204,6 +1223,38 @@ impl Context {
|
||||||
)(input)
|
)(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn tag_bold_italic_asterisk<'a>(&self, input: Span<'a>) -> IResult<Span<'a>, Token> {
|
||||||
|
self.tag_delimited(
|
||||||
|
(tag("***"), FlankingRule::Lenient),
|
||||||
|
(tag("***"), FlankingRule::Lenient),
|
||||||
|
true,
|
||||||
|
Matcher::new(
|
||||||
|
&self.partial(Self::inline_single),
|
||||||
|
&collect_sequence(Token::Sequence, boxing_token(Token::BoldItalic)),
|
||||||
|
),
|
||||||
|
Matcher::new(
|
||||||
|
&self.partial(Self::inline_non_formatting_single),
|
||||||
|
&collect_sequence(Token::Sequence, identity),
|
||||||
|
),
|
||||||
|
)(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tag_bold_italic_underscore<'a>(&self, input: Span<'a>) -> IResult<Span<'a>, Token> {
|
||||||
|
self.tag_delimited(
|
||||||
|
(tag("___"), FlankingRule::Strict),
|
||||||
|
(tag("___"), FlankingRule::Strict),
|
||||||
|
true,
|
||||||
|
Matcher::new(
|
||||||
|
&self.partial(Self::inline_single),
|
||||||
|
&collect_sequence(Token::Sequence, boxing_token(Token::BoldItalic)),
|
||||||
|
),
|
||||||
|
Matcher::new(
|
||||||
|
&self.partial(Self::inline_non_formatting_single),
|
||||||
|
&collect_sequence(Token::Sequence, identity),
|
||||||
|
),
|
||||||
|
)(input)
|
||||||
|
}
|
||||||
|
|
||||||
fn tag_bold<'a>(&self, input: Span<'a>) -> IResult<Span<'a>, Token> {
|
fn tag_bold<'a>(&self, input: Span<'a>) -> IResult<Span<'a>, Token> {
|
||||||
self.tag_delimited(
|
self.tag_delimited(
|
||||||
tag_no_case("<b>"),
|
tag_no_case("<b>"),
|
||||||
|
@ -1447,7 +1498,7 @@ impl Context {
|
||||||
return fail(input);
|
return fail(input);
|
||||||
};
|
};
|
||||||
|
|
||||||
let grapheme = grapheme.trim_end_matches(['\u{200c}', '\u{200d}']);
|
let grapheme = grapheme.trim_end_matches(|c| c == '\u{200c}' || c == '\u{200d}');
|
||||||
|
|
||||||
let emoji = emojis::get(grapheme);
|
let emoji = emojis::get(grapheme);
|
||||||
|
|
||||||
|
@ -1516,7 +1567,7 @@ impl Context {
|
||||||
})(input)?;
|
})(input)?;
|
||||||
|
|
||||||
let (input, name) = map(
|
let (input, name) = map(
|
||||||
recognize(many1(alt((alphanumeric1, recognize(one_of("-_.")))))),
|
recognize(many1(alt((alphanumeric1, recognize(one_of("-_")))))),
|
||||||
Span::into_fragment,
|
Span::into_fragment,
|
||||||
)(input)?;
|
)(input)?;
|
||||||
|
|
||||||
|
@ -1540,7 +1591,7 @@ impl Context {
|
||||||
mention_type
|
mention_type
|
||||||
};
|
};
|
||||||
let host =
|
let host =
|
||||||
host_opt.map(|(_, name)| name.trim_end_matches(['.', '-', '_']));
|
host_opt.map(|(_, name)| name.trim_end_matches(|c| matches!(c, '.' | '-' | '_')));
|
||||||
let input = host.map(|c| before.slice(c.len() + 1..)).unwrap_or(before);
|
let input = host.map(|c| before.slice(c.len() + 1..)).unwrap_or(before);
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
|
@ -1695,7 +1746,7 @@ mod test {
|
||||||
|
|
||||||
use nom::bytes::complete::tag;
|
use nom::bytes::complete::tag;
|
||||||
|
|
||||||
use crate::{to_xml_string, Context, Span, SpanMeta, Token, DEFAULT_DEPTH_LIMIT};
|
use crate::{Context, DEFAULT_DEPTH_LIMIT, Span, SpanMeta, to_xml_string, Token};
|
||||||
|
|
||||||
fn parse_full(string: &str) -> Token {
|
fn parse_full(string: &str) -> Token {
|
||||||
Context::default()
|
Context::default()
|
||||||
|
@ -1853,7 +1904,7 @@ mod test {
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_full(r#"***bold italic***"#),
|
parse_full(r#"***bold italic***"#),
|
||||||
Token::Bold(Box::new(Token::Italic(Box::new(Token::PlainText("bold italic".into())))))
|
Token::BoldItalic(Box::new(Token::PlainText("bold italic".into())))
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|
|
@ -13,7 +13,7 @@ use magnetar_model::model_ext::AliasColumnExt;
|
||||||
use magnetar_model::note_model::data::{
|
use magnetar_model::note_model::data::{
|
||||||
sub_interaction_reaction, sub_interaction_renote, NoteData,
|
sub_interaction_reaction, sub_interaction_renote, NoteData,
|
||||||
};
|
};
|
||||||
use magnetar_model::note_model::{NoteResolveMode, NoteResolveOptions, NoteVisibilityFilterFactory};
|
use magnetar_model::note_model::{NoteResolveOptions, NoteVisibilityFilterFactory};
|
||||||
use magnetar_model::poll::PollResolver;
|
use magnetar_model::poll::PollResolver;
|
||||||
use magnetar_model::sea_orm::sea_query::{PgFunc, Query, SimpleExpr};
|
use magnetar_model::sea_orm::sea_query::{PgFunc, Query, SimpleExpr};
|
||||||
use magnetar_model::sea_orm::{ActiveEnum, ColumnTrait, Iden, IntoSimpleExpr};
|
use magnetar_model::sea_orm::{ActiveEnum, ColumnTrait, Iden, IntoSimpleExpr};
|
||||||
|
@ -518,7 +518,7 @@ impl NoteModel {
|
||||||
let note_resolver = ctx.service.db.get_note_resolver();
|
let note_resolver = ctx.service.db.get_note_resolver();
|
||||||
let Some(note) = note_resolver
|
let Some(note) = note_resolver
|
||||||
.get_one(&NoteResolveOptions {
|
.get_one(&NoteResolveOptions {
|
||||||
mode: Some(NoteResolveMode::Single(id.to_owned())),
|
ids: Some(vec![id.to_owned()]),
|
||||||
visibility_filter: Arc::new(NoteVisibilityFilterModel.new_note_visibility_filter(
|
visibility_filter: Arc::new(NoteVisibilityFilterModel.new_note_visibility_filter(
|
||||||
ctx.self_user.as_deref().map(ck::user::Model::get_id),
|
ctx.self_user.as_deref().map(ck::user::Model::get_id),
|
||||||
)),
|
)),
|
||||||
|
@ -540,6 +540,7 @@ impl NoteModel {
|
||||||
.map(str::to_string)
|
.map(str::to_string)
|
||||||
})
|
})
|
||||||
.flatten(),
|
.flatten(),
|
||||||
|
only_pins_from: None,
|
||||||
})
|
})
|
||||||
.await?
|
.await?
|
||||||
else {
|
else {
|
||||||
|
@ -557,7 +558,7 @@ impl NoteModel {
|
||||||
let note_resolver = ctx.service.db.get_note_resolver();
|
let note_resolver = ctx.service.db.get_note_resolver();
|
||||||
let notes = note_resolver
|
let notes = note_resolver
|
||||||
.get_many(&NoteResolveOptions {
|
.get_many(&NoteResolveOptions {
|
||||||
mode: Some(NoteResolveMode::PinsFromUserId(pin_user.id.clone())),
|
ids: None,
|
||||||
visibility_filter: Arc::new(NoteVisibilityFilterModel.new_note_visibility_filter(
|
visibility_filter: Arc::new(NoteVisibilityFilterModel.new_note_visibility_filter(
|
||||||
ctx.self_user.as_deref().map(ck::user::Model::get_id),
|
ctx.self_user.as_deref().map(ck::user::Model::get_id),
|
||||||
)),
|
)),
|
||||||
|
@ -579,6 +580,7 @@ impl NoteModel {
|
||||||
.map(str::to_string)
|
.map(str::to_string)
|
||||||
})
|
})
|
||||||
.flatten(),
|
.flatten(),
|
||||||
|
only_pins_from: Some(pin_user.id.clone()),
|
||||||
})
|
})
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
|
|
@ -231,7 +231,7 @@ impl NotificationModel {
|
||||||
.get_single(
|
.get_single(
|
||||||
&NotificationResolveOptions {
|
&NotificationResolveOptions {
|
||||||
note_options: NoteResolveOptions {
|
note_options: NoteResolveOptions {
|
||||||
mode: None,
|
ids: None,
|
||||||
visibility_filter: Arc::new(
|
visibility_filter: Arc::new(
|
||||||
NoteVisibilityFilterModel.new_note_visibility_filter(Some(user_id)),
|
NoteVisibilityFilterModel.new_note_visibility_filter(Some(user_id)),
|
||||||
),
|
),
|
||||||
|
@ -240,6 +240,7 @@ impl NotificationModel {
|
||||||
with_reply_target: true,
|
with_reply_target: true,
|
||||||
with_renote_target: true,
|
with_renote_target: true,
|
||||||
with_interactions_from: self_id.map(str::to_string),
|
with_interactions_from: self_id.map(str::to_string),
|
||||||
|
only_pins_from: None,
|
||||||
user_options: user_resolve_options.clone(),
|
user_options: user_resolve_options.clone(),
|
||||||
},
|
},
|
||||||
user_options: user_resolve_options,
|
user_options: user_resolve_options,
|
||||||
|
@ -293,7 +294,7 @@ impl NotificationModel {
|
||||||
.get(
|
.get(
|
||||||
&NotificationResolveOptions {
|
&NotificationResolveOptions {
|
||||||
note_options: NoteResolveOptions {
|
note_options: NoteResolveOptions {
|
||||||
mode: None,
|
ids: None,
|
||||||
visibility_filter: Arc::new(
|
visibility_filter: Arc::new(
|
||||||
NoteVisibilityFilterModel.new_note_visibility_filter(Some(id)),
|
NoteVisibilityFilterModel.new_note_visibility_filter(Some(id)),
|
||||||
),
|
),
|
||||||
|
@ -302,6 +303,7 @@ impl NotificationModel {
|
||||||
with_reply_target: true,
|
with_reply_target: true,
|
||||||
with_renote_target: true,
|
with_renote_target: true,
|
||||||
with_interactions_from: self_id.map(str::to_string),
|
with_interactions_from: self_id.map(str::to_string),
|
||||||
|
only_pins_from: None,
|
||||||
user_options: user_resolve_options.clone(),
|
user_options: user_resolve_options.clone(),
|
||||||
},
|
},
|
||||||
user_options: user_resolve_options,
|
user_options: user_resolve_options,
|
||||||
|
|
|
@ -4,11 +4,11 @@ use magnetar_model::emoji::{EmojiResolver, EmojiTag};
|
||||||
use magnetar_model::{ck, CalckeyDbError, CalckeyModel};
|
use magnetar_model::{ck, CalckeyDbError, CalckeyModel};
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use strum::VariantNames;
|
use strum::EnumVariantNames;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
#[derive(Debug, Error, VariantNames)]
|
#[derive(Debug, Error, EnumVariantNames)]
|
||||||
pub enum EmojiCacheError {
|
pub enum EmojiCacheError {
|
||||||
#[error("Database error: {0}")]
|
#[error("Database error: {0}")]
|
||||||
DbError(#[from] CalckeyDbError),
|
DbError(#[from] CalckeyDbError),
|
||||||
|
|
|
@ -5,11 +5,11 @@ use magnetar_model::{CalckeyDbError, CalckeyModel};
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
use strum::VariantNames;
|
use strum::EnumVariantNames;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
#[derive(Debug, Error, VariantNames)]
|
#[derive(Debug, Error, EnumVariantNames)]
|
||||||
pub enum GenericIdCacheError {
|
pub enum GenericIdCacheError {
|
||||||
#[error("Database error: {0}")]
|
#[error("Database error: {0}")]
|
||||||
DbError(#[from] CalckeyDbError),
|
DbError(#[from] CalckeyDbError),
|
||||||
|
|
|
@ -4,11 +4,11 @@ use magnetar_common::config::MagnetarConfig;
|
||||||
use magnetar_model::{ck, CalckeyDbError, CalckeyModel};
|
use magnetar_model::{ck, CalckeyDbError, CalckeyModel};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
use strum::VariantNames;
|
use strum::EnumVariantNames;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
#[derive(Debug, Error, VariantNames)]
|
#[derive(Debug, Error, EnumVariantNames)]
|
||||||
pub enum RemoteInstanceCacheError {
|
pub enum RemoteInstanceCacheError {
|
||||||
#[error("Database error: {0}")]
|
#[error("Database error: {0}")]
|
||||||
DbError(#[from] CalckeyDbError),
|
DbError(#[from] CalckeyDbError),
|
||||||
|
|
|
@ -2,12 +2,12 @@ use crate::web::ApiError;
|
||||||
use magnetar_model::{ck, CalckeyDbError, CalckeyModel};
|
use magnetar_model::{ck, CalckeyDbError, CalckeyModel};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
use strum::VariantNames;
|
use strum::EnumVariantNames;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use tokio::sync::{mpsc, oneshot};
|
use tokio::sync::{mpsc, oneshot};
|
||||||
use tracing::error;
|
use tracing::error;
|
||||||
|
|
||||||
#[derive(Debug, Error, VariantNames)]
|
#[derive(Debug, Error, EnumVariantNames)]
|
||||||
pub enum InstanceMetaCacheError {
|
pub enum InstanceMetaCacheError {
|
||||||
#[error("Database error: {0}")]
|
#[error("Database error: {0}")]
|
||||||
DbError(#[from] CalckeyDbError),
|
DbError(#[from] CalckeyDbError),
|
||||||
|
|
|
@ -2,20 +2,20 @@ use std::collections::HashMap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use cached::{Cached, TimedCache};
|
use cached::{Cached, TimedCache};
|
||||||
use strum::{EnumVariantNames, VariantNames};
|
use strum::EnumVariantNames;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
use tracing::error;
|
use tracing::error;
|
||||||
|
|
||||||
use magnetar_common::config::MagnetarConfig;
|
use magnetar_common::config::MagnetarConfig;
|
||||||
use magnetar_model::{
|
use magnetar_model::{
|
||||||
ck, CalckeyCache, CalckeyCacheError, CalckeyDbError, CalckeyModel, CalckeySub,
|
CalckeyCache, CalckeyCacheError, CalckeyDbError, CalckeyModel, CalckeySub, ck,
|
||||||
InternalStreamMessage, SubMessage,
|
InternalStreamMessage, SubMessage,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::web::ApiError;
|
use crate::web::ApiError;
|
||||||
|
|
||||||
#[derive(Debug, Error, VariantNames)]
|
#[derive(Debug, Error, EnumVariantNames)]
|
||||||
pub enum UserCacheError {
|
pub enum UserCacheError {
|
||||||
#[error("Database error: {0}")]
|
#[error("Database error: {0}")]
|
||||||
DbError(#[from] CalckeyDbError),
|
DbError(#[from] CalckeyDbError),
|
||||||
|
|
Loading…
Reference in New Issue