magnetar/magnetar_sdk/src/types/mod.rs

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_utc(
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,
}