231 lines
6.2 KiB
Rust
231 lines
6.2 KiB
Rust
pub mod drive;
|
|
pub mod emoji;
|
|
pub mod instance;
|
|
pub mod note;
|
|
pub mod notification;
|
|
pub mod timeline;
|
|
pub mod user;
|
|
|
|
use crate::types::notification::NotificationType;
|
|
use crate::util_types::U64Range;
|
|
use chrono::{DateTime, Utc};
|
|
use serde::de::Error;
|
|
use serde::{Deserialize, Deserializer, Serialize};
|
|
use ts_rs::TS;
|
|
|
|
pub(crate) mod packed_time {
|
|
use chrono::{DateTime, NaiveDateTime, Utc};
|
|
use serde::de::Error;
|
|
use serde::{Deserialize, Deserializer, Serializer};
|
|
|
|
pub(crate) fn serialize<S>(value: &DateTime<Utc>, serializer: S) -> Result<S::Ok, S::Error>
|
|
where
|
|
S: Serializer,
|
|
{
|
|
serializer.serialize_str(&value.timestamp_millis().to_string())
|
|
}
|
|
|
|
pub(crate) fn deserialize<'de, D>(deserializer: D) -> Result<DateTime<Utc>, D::Error>
|
|
where
|
|
D: Deserializer<'de>,
|
|
{
|
|
Ok(DateTime::<Utc>::from_naive_utc_and_offset(
|
|
NaiveDateTime::from_timestamp_millis(
|
|
String::deserialize(deserializer)?
|
|
.parse::<i64>()
|
|
.map_err(Error::custom)?,
|
|
)
|
|
.ok_or_else(|| Error::custom("millisecond value out of range"))?,
|
|
Utc,
|
|
))
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Debug, Deserialize, Serialize, TS)]
|
|
#[ts(export)]
|
|
pub struct RangeFilter {
|
|
#[serde(with = "packed_time")]
|
|
pub time_start: DateTime<Utc>,
|
|
#[serde(with = "packed_time")]
|
|
pub time_end: DateTime<Utc>,
|
|
pub id_start: String,
|
|
pub id_end: String,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Deserialize, Serialize, TS)]
|
|
#[ts(export)]
|
|
pub struct StartFilter {
|
|
#[serde(with = "packed_time")]
|
|
pub time_start: DateTime<Utc>,
|
|
pub id_start: String,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Deserialize, Serialize, TS)]
|
|
#[ts(export)]
|
|
pub struct EndFilter {
|
|
#[serde(with = "packed_time")]
|
|
pub time_end: DateTime<Utc>,
|
|
pub id_end: String,
|
|
}
|
|
|
|
#[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),
|
|
}
|
|
|
|
impl SpanFilter {
|
|
pub fn is_desc(&self) -> bool {
|
|
!matches!(self, Self::Start(_))
|
|
}
|
|
|
|
pub fn start(&self) -> Option<(DateTime<Utc>, String)> {
|
|
match self {
|
|
Self::Start(StartFilter {
|
|
time_start,
|
|
id_start,
|
|
})
|
|
| Self::Range(RangeFilter {
|
|
time_start,
|
|
id_start,
|
|
..
|
|
}) => Some((*time_start, id_start.clone())),
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
pub fn end(&self) -> Option<(DateTime<Utc>, String)> {
|
|
match self {
|
|
Self::End(EndFilter { time_end, id_end })
|
|
| Self::Range(RangeFilter {
|
|
time_end, id_end, ..
|
|
}) => Some((*time_end, id_end.clone())),
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
pub fn prev(&self, first_date: DateTime<Utc>, first_id: &str) -> Option<SpanFilter> {
|
|
match self {
|
|
Self::Start(_) => Some(SpanFilter::End(EndFilter {
|
|
time_end: first_date,
|
|
id_end: first_id.to_string(),
|
|
})),
|
|
Self::End(_) => Some(SpanFilter::Start(StartFilter {
|
|
time_start: first_date,
|
|
id_start: first_id.to_string(),
|
|
})),
|
|
// TODO: This is jank
|
|
// It forgets the bounds of the cursor
|
|
Self::Range(_) => Some(SpanFilter::Start(StartFilter {
|
|
time_start: first_date,
|
|
id_start: first_id.to_string(),
|
|
})),
|
|
Self::None(_) => None,
|
|
}
|
|
}
|
|
|
|
pub fn next(&self, last_date: DateTime<Utc>, last_id: &str) -> Option<SpanFilter> {
|
|
match self {
|
|
Self::Start(_) => Some(SpanFilter::Start(StartFilter {
|
|
time_start: last_date,
|
|
id_start: last_id.to_string(),
|
|
})),
|
|
Self::End(_) | Self::None(_) => Some(SpanFilter::End(EndFilter {
|
|
time_end: last_date,
|
|
id_end: last_id.to_string(),
|
|
})),
|
|
Self::Range(RangeFilter { time_start, .. }) if *time_start > last_date => None,
|
|
Self::Range(RangeFilter {
|
|
time_start,
|
|
id_start,
|
|
..
|
|
}) => Some(SpanFilter::Range(RangeFilter {
|
|
time_start: *time_start,
|
|
id_start: id_start.clone(),
|
|
time_end: last_date,
|
|
id_end: last_id.to_string(),
|
|
})),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Debug, Deserialize, Serialize, TS)]
|
|
#[ts(export)]
|
|
pub struct PaginationShape {
|
|
#[serde(default = "pagination_default")]
|
|
#[serde(deserialize_with = "deserialize_pagination")]
|
|
pub pagination: SpanFilter,
|
|
#[serde(default = "limit_defalt")]
|
|
#[serde(deserialize_with = "deserialize_limit")]
|
|
pub limit: U64Range<10, 100>,
|
|
}
|
|
|
|
fn pagination_default() -> SpanFilter {
|
|
SpanFilter::None(NoFilter {})
|
|
}
|
|
|
|
fn limit_defalt() -> U64Range<10, 100> {
|
|
U64Range::try_from(20).unwrap()
|
|
}
|
|
|
|
fn deserialize_limit<'de, D>(deserializer: D) -> Result<U64Range<10, 100>, D::Error>
|
|
where
|
|
D: Deserializer<'de>,
|
|
{
|
|
let str_val = String::deserialize(deserializer)?;
|
|
|
|
U64Range::try_from(str_val.parse::<u64>().map_err(Error::custom)?)
|
|
.map_err(|_| Error::custom("number out of range"))
|
|
}
|
|
|
|
fn deserialize_pagination<'de, D>(deserializer: D) -> Result<SpanFilter, D::Error>
|
|
where
|
|
D: Deserializer<'de>,
|
|
{
|
|
let str_val = String::deserialize(deserializer)?;
|
|
|
|
serde_urlencoded::from_str::<SpanFilter>(&str_val).map_err(Error::custom)
|
|
}
|
|
|
|
#[derive(Clone, Debug, Deserialize, Serialize, TS)]
|
|
#[ts(export)]
|
|
#[repr(transparent)]
|
|
pub struct Id {
|
|
pub id: String,
|
|
}
|
|
|
|
impl<T: AsRef<str>> From<T> for Id {
|
|
fn from(id: T) -> Self {
|
|
Self {
|
|
id: id.as_ref().to_string(),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Debug, Deserialize, Serialize, TS)]
|
|
#[ts(export)]
|
|
#[repr(transparent)]
|
|
pub struct MmXml(pub String);
|
|
|
|
#[derive(Clone, Debug, Deserialize, Serialize, TS)]
|
|
#[ts(export)]
|
|
pub struct NotificationSettings {
|
|
pub enabled: Vec<NotificationType>,
|
|
}
|
|
|
|
#[derive(Copy, Clone, Debug, Deserialize, Serialize, TS)]
|
|
#[ts(export)]
|
|
pub enum FollowVisibility {
|
|
Public,
|
|
Followers,
|
|
Private,
|
|
}
|