2024-05-13 21:31:33 +02:00
|
|
|
extern crate serde; // 1.0.68
|
|
|
|
|
extern crate serde_derive; // 1.0.68
|
|
|
|
|
|
|
|
|
|
use std::{
|
|
|
|
|
collections::HashMap,
|
|
|
|
|
fmt::{Display, Formatter},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
use serde::{ser::SerializeMap, Deserialize, Deserializer, Serialize, Serializer};
|
|
|
|
|
|
|
|
|
|
use time::{
|
|
|
|
|
format_description::well_known::{iso8601, Iso8601},
|
|
|
|
|
OffsetDateTime,
|
|
|
|
|
};
|
2024-05-09 23:09:10 +02:00
|
|
|
use url::Url;
|
2024-06-18 03:56:25 +02:00
|
|
|
use uuid::Uuid;
|
2024-05-09 23:09:10 +02:00
|
|
|
|
2024-05-13 21:31:33 +02:00
|
|
|
const FORMAT: Iso8601<6651332276412969266533270467398074368> = Iso8601::<
|
|
|
|
|
{
|
|
|
|
|
iso8601::Config::DEFAULT
|
|
|
|
|
.set_year_is_six_digits(false)
|
|
|
|
|
.encode()
|
|
|
|
|
},
|
|
|
|
|
>;
|
2024-08-28 15:24:22 +02:00
|
|
|
time::serde::format_description!(iso_versia, OffsetDateTime, FORMAT);
|
2024-05-13 21:31:33 +02:00
|
|
|
|
|
|
|
|
fn sort_alphabetically<T: Serialize, S: serde::Serializer>(
|
|
|
|
|
value: &T,
|
|
|
|
|
serializer: S,
|
|
|
|
|
) -> Result<S::Ok, S::Error> {
|
|
|
|
|
let value = serde_json::to_value(value).map_err(serde::ser::Error::custom)?;
|
|
|
|
|
value.serialize(serializer)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Serialize)]
|
|
|
|
|
pub struct SortAlphabetically<T: Serialize>(#[serde(serialize_with = "sort_alphabetically")] pub T);
|
|
|
|
|
|
2024-06-18 03:56:25 +02:00
|
|
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
2024-11-24 17:09:03 +01:00
|
|
|
#[serde(rename_all = "lowercase")]
|
2024-06-18 03:56:25 +02:00
|
|
|
pub enum CategoryType {
|
|
|
|
|
Microblog,
|
|
|
|
|
Forum,
|
|
|
|
|
Blog,
|
|
|
|
|
Image,
|
|
|
|
|
Video,
|
|
|
|
|
Audio,
|
|
|
|
|
Messaging,
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-13 22:08:23 +02:00
|
|
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
2024-08-28 15:24:22 +02:00
|
|
|
pub enum VersiaExtensions {
|
2024-11-19 22:15:19 +01:00
|
|
|
#[serde(rename = "pub.versia:share/Share")]
|
|
|
|
|
Share,
|
2024-08-28 16:24:39 +02:00
|
|
|
#[serde(rename = "pub.versia:custom_emojis")]
|
2024-05-13 22:08:23 +02:00
|
|
|
CustomEmojis,
|
2024-08-28 16:24:39 +02:00
|
|
|
#[serde(rename = "pub.versia:reactions/Reaction")]
|
2024-05-13 22:08:23 +02:00
|
|
|
Reaction,
|
2024-08-28 16:24:39 +02:00
|
|
|
#[serde(rename = "pub.versia:reactions")]
|
2024-05-13 22:08:23 +02:00
|
|
|
Reactions,
|
2024-08-28 16:24:39 +02:00
|
|
|
#[serde(rename = "pub.versia:polls")]
|
2024-05-13 22:08:23 +02:00
|
|
|
Polls,
|
2024-08-28 16:24:39 +02:00
|
|
|
#[serde(rename = "pub.versia:is_cat")]
|
2024-05-13 22:08:23 +02:00
|
|
|
IsCat,
|
2024-08-28 16:24:39 +02:00
|
|
|
#[serde(rename = "pub.versia:server_endorsement/Endorsement")]
|
2024-05-13 22:08:23 +02:00
|
|
|
Endorsement,
|
2024-08-28 16:24:39 +02:00
|
|
|
#[serde(rename = "pub.versia:server_endorsement")]
|
2024-05-13 22:08:23 +02:00
|
|
|
EndorsementCollection,
|
2024-08-28 16:24:39 +02:00
|
|
|
#[serde(rename = "pub.versia:reports/Report")]
|
2024-05-13 22:08:23 +02:00
|
|
|
Report,
|
2024-08-28 16:24:39 +02:00
|
|
|
#[serde(rename = "pub.versia:vanity")]
|
2024-05-13 22:08:23 +02:00
|
|
|
Vanity,
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-13 21:31:33 +02:00
|
|
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
|
|
|
|
pub struct PublicKey {
|
2024-11-19 22:15:19 +01:00
|
|
|
pub key: String,
|
2024-07-16 19:35:04 +02:00
|
|
|
pub actor: Url,
|
2024-11-19 22:15:19 +01:00
|
|
|
pub algorithm: String,
|
2024-05-13 21:31:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
|
|
|
|
pub struct ContentHash {
|
|
|
|
|
md5: Option<String>,
|
|
|
|
|
sha1: Option<String>,
|
|
|
|
|
sha256: Option<String>,
|
|
|
|
|
sha512: Option<String>,
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-16 19:35:04 +02:00
|
|
|
#[derive(Debug, Clone, Default)]
|
2024-06-18 03:56:25 +02:00
|
|
|
pub struct ContentFormat {
|
2024-07-16 19:35:04 +02:00
|
|
|
pub x: HashMap<String, ContentEntry>,
|
2024-05-13 21:31:33 +02:00
|
|
|
}
|
|
|
|
|
|
2024-06-18 03:56:25 +02:00
|
|
|
impl ContentFormat {
|
|
|
|
|
pub async fn select_rich_text(&self) -> anyhow::Result<String> {
|
|
|
|
|
if let Some(entry) = self.x.get("text/x.misskeymarkdown") {
|
|
|
|
|
return Ok(entry.content.clone());
|
|
|
|
|
}
|
|
|
|
|
if let Some(entry) = self.x.get("text/html") {
|
|
|
|
|
return Ok(entry.content.clone());
|
|
|
|
|
}
|
|
|
|
|
if let Some(entry) = self.x.get("text/markdown") {
|
|
|
|
|
return Ok(entry.content.clone());
|
|
|
|
|
}
|
|
|
|
|
if let Some(entry) = self.x.get("text/plain") {
|
|
|
|
|
return Ok(entry.content.clone());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ok(self.x.clone().values().next().unwrap().content.clone())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub async fn select_rich_img(&self) -> anyhow::Result<String> {
|
|
|
|
|
if let Some(entry) = self.x.get("image/webp") {
|
|
|
|
|
return Ok(entry.content.clone());
|
|
|
|
|
}
|
|
|
|
|
if let Some(entry) = self.x.get("image/png") {
|
|
|
|
|
return Ok(entry.content.clone());
|
|
|
|
|
}
|
|
|
|
|
if let Some(entry) = self.x.get("image/avif") {
|
|
|
|
|
return Ok(entry.content.clone());
|
|
|
|
|
}
|
|
|
|
|
if let Some(entry) = self.x.get("image/jxl") {
|
|
|
|
|
return Ok(entry.content.clone());
|
|
|
|
|
}
|
|
|
|
|
if let Some(entry) = self.x.get("image/jpeg") {
|
|
|
|
|
return Ok(entry.content.clone());
|
|
|
|
|
}
|
|
|
|
|
if let Some(entry) = self.x.get("image/gif") {
|
|
|
|
|
return Ok(entry.content.clone());
|
|
|
|
|
}
|
|
|
|
|
if let Some(entry) = self.x.get("image/bmp") {
|
|
|
|
|
return Ok(entry.content.clone());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ok(self.x.clone().values().next().unwrap().content.clone())
|
|
|
|
|
}
|
2024-07-21 19:37:08 +02:00
|
|
|
|
|
|
|
|
pub async fn select_rich_img_touple(&self) -> anyhow::Result<(String, String)> {
|
|
|
|
|
if let Some(entry) = self.x.get("image/webp") {
|
|
|
|
|
return Ok(("image/webp".to_string(), entry.content.clone()));
|
|
|
|
|
}
|
|
|
|
|
if let Some(entry) = self.x.get("image/png") {
|
|
|
|
|
return Ok(("image/png".to_string(), entry.content.clone()));
|
|
|
|
|
}
|
|
|
|
|
if let Some(entry) = self.x.get("image/avif") {
|
|
|
|
|
return Ok(("image/avif".to_string(), entry.content.clone()));
|
|
|
|
|
}
|
|
|
|
|
if let Some(entry) = self.x.get("image/jxl") {
|
|
|
|
|
return Ok(("image/jxl".to_string(), entry.content.clone()));
|
|
|
|
|
}
|
|
|
|
|
if let Some(entry) = self.x.get("image/jpeg") {
|
|
|
|
|
return Ok(("image/jpeg".to_string(), entry.content.clone()));
|
|
|
|
|
}
|
|
|
|
|
if let Some(entry) = self.x.get("image/gif") {
|
|
|
|
|
return Ok(("image/gif".to_string(), entry.content.clone()));
|
|
|
|
|
}
|
|
|
|
|
if let Some(entry) = self.x.get("image/bmp") {
|
|
|
|
|
return Ok(("image/bmp".to_string(), entry.content.clone()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let touple = self.x.iter().next().unwrap();
|
|
|
|
|
|
|
|
|
|
Ok((touple.0.clone(), touple.1.content.clone()))
|
|
|
|
|
}
|
2024-06-18 03:56:25 +02:00
|
|
|
}
|
|
|
|
|
|
2024-05-13 21:31:33 +02:00
|
|
|
impl Serialize for ContentFormat {
|
|
|
|
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
|
|
|
where
|
|
|
|
|
S: Serializer,
|
|
|
|
|
{
|
|
|
|
|
let mut seq = serializer.serialize_map(Some(self.x.len()))?;
|
|
|
|
|
for (k, v) in &self.x {
|
|
|
|
|
seq.serialize_entry(&k.to_string(), &v)?;
|
|
|
|
|
}
|
|
|
|
|
seq.end()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
impl<'de> Deserialize<'de> for ContentFormat {
|
|
|
|
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
|
|
|
where
|
|
|
|
|
D: Deserializer<'de>,
|
|
|
|
|
{
|
|
|
|
|
let map = HashMap::deserialize(deserializer)?;
|
|
|
|
|
Ok(ContentFormat { x: map })
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
2024-07-16 19:35:04 +02:00
|
|
|
pub struct FieldKV {
|
2024-07-21 19:37:08 +02:00
|
|
|
pub key: ContentFormat,
|
|
|
|
|
pub value: ContentFormat,
|
2024-05-13 21:31:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
|
|
|
|
pub struct ContentEntry {
|
|
|
|
|
content: String,
|
2024-11-19 22:15:19 +01:00
|
|
|
remote: bool,
|
2024-07-26 00:26:13 +02:00
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
2024-05-13 21:31:33 +02:00
|
|
|
description: Option<String>,
|
2024-07-26 00:26:13 +02:00
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
2024-05-13 21:31:33 +02:00
|
|
|
size: Option<u64>,
|
2024-07-26 00:26:13 +02:00
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
2024-05-13 21:31:33 +02:00
|
|
|
hash: Option<ContentHash>,
|
2024-07-26 00:26:13 +02:00
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
2024-05-13 21:31:33 +02:00
|
|
|
blurhash: Option<String>,
|
2024-07-26 00:26:13 +02:00
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
2024-05-13 21:31:33 +02:00
|
|
|
fps: Option<u64>,
|
2024-07-26 00:26:13 +02:00
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
2024-05-13 21:31:33 +02:00
|
|
|
width: Option<u64>,
|
2024-07-26 00:26:13 +02:00
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
2024-05-13 21:31:33 +02:00
|
|
|
height: Option<u64>,
|
2024-07-26 00:26:13 +02:00
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
2024-05-13 21:31:33 +02:00
|
|
|
duration: Option<u64>,
|
|
|
|
|
}
|
2024-07-16 19:35:04 +02:00
|
|
|
impl ContentEntry {
|
|
|
|
|
pub fn from_string(string: String) -> ContentEntry {
|
|
|
|
|
ContentEntry {
|
|
|
|
|
content: string,
|
2024-11-19 22:15:19 +01:00
|
|
|
remote: false,
|
2024-07-16 19:35:04 +02:00
|
|
|
description: None,
|
|
|
|
|
size: None,
|
|
|
|
|
hash: None,
|
|
|
|
|
blurhash: None,
|
|
|
|
|
fps: None,
|
|
|
|
|
width: None,
|
|
|
|
|
height: None,
|
|
|
|
|
duration: None,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-05-13 21:31:33 +02:00
|
|
|
|
|
|
|
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
|
|
|
|
pub struct User {
|
2024-06-18 03:56:25 +02:00
|
|
|
pub public_key: PublicKey,
|
2024-05-13 21:31:33 +02:00
|
|
|
#[serde(rename = "type")]
|
2024-11-19 22:15:19 +01:00
|
|
|
pub rtype: String,
|
2024-06-18 03:56:25 +02:00
|
|
|
pub id: Uuid,
|
|
|
|
|
pub uri: Url,
|
2024-08-28 15:24:22 +02:00
|
|
|
#[serde(with = "iso_versia")]
|
2024-06-18 03:56:25 +02:00
|
|
|
pub created_at: OffsetDateTime,
|
2024-07-26 00:26:13 +02:00
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
2024-06-18 03:56:25 +02:00
|
|
|
pub display_name: Option<String>,
|
2024-11-19 22:15:19 +01:00
|
|
|
pub collections: UserCollections,
|
2024-06-18 03:56:25 +02:00
|
|
|
pub inbox: Url,
|
|
|
|
|
pub username: String,
|
2024-07-26 00:26:13 +02:00
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
2024-06-18 03:56:25 +02:00
|
|
|
pub bio: Option<ContentFormat>,
|
2024-07-26 00:26:13 +02:00
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
2024-06-18 03:56:25 +02:00
|
|
|
pub avatar: Option<ContentFormat>,
|
2024-07-26 00:26:13 +02:00
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
2024-06-18 03:56:25 +02:00
|
|
|
pub header: Option<ContentFormat>,
|
2024-07-26 00:26:13 +02:00
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
2024-06-18 03:56:25 +02:00
|
|
|
pub fields: Option<Vec<FieldKV>>,
|
2024-07-16 23:22:52 +02:00
|
|
|
pub indexable: bool,
|
2024-07-26 00:26:13 +02:00
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
2024-07-21 19:37:08 +02:00
|
|
|
pub extensions: Option<ExtensionSpecs>,
|
2024-11-19 22:15:19 +01:00
|
|
|
pub manually_approves_followers: bool,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
|
|
|
|
pub struct UserCollections {
|
|
|
|
|
pub outbox: Url,
|
|
|
|
|
pub featured: Url,
|
|
|
|
|
pub followers: Url,
|
|
|
|
|
pub following: Url,
|
2024-11-23 14:31:02 +01:00
|
|
|
#[serde(
|
|
|
|
|
skip_serializing_if = "Option::is_none",
|
2025-02-11 14:03:32 +01:00
|
|
|
rename = "pub.versia:likes/Likes"
|
2024-11-23 14:31:02 +01:00
|
|
|
)]
|
|
|
|
|
pub likes: Option<Url>,
|
|
|
|
|
#[serde(
|
|
|
|
|
skip_serializing_if = "Option::is_none",
|
2025-02-11 14:03:32 +01:00
|
|
|
rename = "pub.versia:likes/Dislikes"
|
2024-11-23 14:31:02 +01:00
|
|
|
)]
|
|
|
|
|
pub dislikes: Option<Url>,
|
2024-07-21 19:37:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
|
|
|
|
pub struct ExtensionSpecs {
|
2024-08-28 16:24:39 +02:00
|
|
|
#[serde(rename = "pub.versia:custom_emojis")]
|
2024-07-26 00:26:13 +02:00
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
2024-07-21 19:37:08 +02:00
|
|
|
pub custom_emojis: Option<CustomEmojis>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
|
|
|
|
pub struct CustomEmojis {
|
|
|
|
|
pub emojis: Vec<CustomEmoji>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
|
|
|
|
pub struct CustomEmoji {
|
|
|
|
|
pub name: String,
|
|
|
|
|
pub url: ContentFormat,
|
2024-06-18 03:56:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
|
|
|
|
pub struct DeviceInfo {
|
|
|
|
|
name: String,
|
|
|
|
|
version: String,
|
|
|
|
|
url: Url,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
|
|
|
|
pub struct LinkPreview {
|
|
|
|
|
description: String,
|
|
|
|
|
title: String,
|
|
|
|
|
link: Url,
|
2024-07-26 00:26:13 +02:00
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
2024-06-18 03:56:25 +02:00
|
|
|
image: Option<Url>,
|
2024-07-26 00:26:13 +02:00
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
2024-06-18 03:56:25 +02:00
|
|
|
icon: Option<Url>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
|
|
|
|
pub struct Note {
|
|
|
|
|
#[serde(rename = "type")]
|
2024-11-19 22:15:19 +01:00
|
|
|
pub rtype: String,
|
2024-07-27 16:24:04 +02:00
|
|
|
pub id: Uuid,
|
|
|
|
|
pub uri: Url,
|
|
|
|
|
pub author: Url,
|
2024-08-28 15:24:22 +02:00
|
|
|
#[serde(with = "iso_versia")]
|
2024-07-27 16:24:04 +02:00
|
|
|
pub created_at: OffsetDateTime,
|
|
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
|
|
|
pub category: Option<CategoryType>,
|
|
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
|
|
|
pub content: Option<ContentFormat>,
|
|
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
|
|
|
pub device: Option<DeviceInfo>,
|
|
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
|
|
|
pub previews: Option<Vec<LinkPreview>>,
|
|
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
|
|
|
pub group: Option<String>,
|
|
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
|
|
|
pub attachments: Option<Vec<ContentFormat>>,
|
|
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
|
|
|
pub replies_to: Option<Url>,
|
|
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
|
|
|
pub quotes: Option<Url>,
|
|
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
|
|
|
pub mentions: Option<Vec<Url>>,
|
|
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
|
|
|
pub subject: Option<String>,
|
|
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
|
|
|
pub is_sensitive: Option<bool>,
|
|
|
|
|
//TODO extensions
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-18 03:56:25 +02:00
|
|
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
|
|
|
|
pub struct Outbox {
|
|
|
|
|
pub first: Url,
|
|
|
|
|
pub last: Url,
|
2024-07-26 00:26:13 +02:00
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
2024-06-18 03:56:25 +02:00
|
|
|
pub next: Option<Url>,
|
2024-07-26 00:26:13 +02:00
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
2024-11-19 22:15:19 +01:00
|
|
|
pub previous: Option<Url>,
|
2024-06-18 03:56:25 +02:00
|
|
|
pub items: Vec<Note>,
|
2024-05-09 23:10:36 +02:00
|
|
|
}
|
2024-07-27 16:24:04 +02:00
|
|
|
|
|
|
|
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
|
|
|
|
pub struct Follow {
|
|
|
|
|
#[serde(rename = "type")]
|
2024-11-19 22:15:19 +01:00
|
|
|
pub rtype: String,
|
2024-07-27 16:24:04 +02:00
|
|
|
pub id: Uuid,
|
|
|
|
|
pub uri: Url,
|
|
|
|
|
pub author: Url,
|
2024-08-28 15:24:22 +02:00
|
|
|
#[serde(with = "iso_versia")]
|
2024-07-27 16:24:04 +02:00
|
|
|
pub created_at: OffsetDateTime,
|
|
|
|
|
pub followee: Url,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
|
|
|
|
pub struct FollowResult {
|
|
|
|
|
#[serde(rename = "type")]
|
2024-11-19 22:15:19 +01:00
|
|
|
pub rtype: String,
|
2024-07-27 16:24:04 +02:00
|
|
|
pub id: Uuid,
|
|
|
|
|
pub uri: Url,
|
|
|
|
|
pub author: Url,
|
2024-08-28 15:24:22 +02:00
|
|
|
#[serde(with = "iso_versia")]
|
2024-07-27 16:24:04 +02:00
|
|
|
pub created_at: OffsetDateTime,
|
|
|
|
|
pub follower: Url,
|
|
|
|
|
}
|
2024-11-19 22:15:19 +01:00
|
|
|
|
|
|
|
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
|
|
|
|
pub struct Unfollow {
|
|
|
|
|
#[serde(rename = "type")]
|
|
|
|
|
pub rtype: String,
|
|
|
|
|
pub id: Uuid,
|
|
|
|
|
pub author: Url,
|
|
|
|
|
#[serde(with = "iso_versia")]
|
|
|
|
|
pub created_at: OffsetDateTime,
|
|
|
|
|
pub followee: Url,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
|
|
|
|
pub struct Delete {
|
|
|
|
|
#[serde(rename = "type")]
|
|
|
|
|
pub rtype: String,
|
|
|
|
|
pub id: Uuid,
|
|
|
|
|
pub author: Option<Url>,
|
|
|
|
|
#[serde(with = "iso_versia")]
|
|
|
|
|
pub created_at: OffsetDateTime,
|
|
|
|
|
pub deleted_type: String,
|
|
|
|
|
pub deleted: Url,
|
|
|
|
|
}
|