feat: initial port to WD4

This commit is contained in:
aprilthepink 2024-11-19 22:15:19 +01:00
parent 084e85e111
commit c72763c4b1
6 changed files with 96 additions and 126 deletions

View file

@ -6,6 +6,7 @@ use chrono::{DateTime, TimeZone, Utc};
use reqwest::header::{self, CONTENT_TYPE}; use reqwest::header::{self, CONTENT_TYPE};
use sea_orm::{ActiveModelTrait, ColumnTrait, EntityTrait, QueryFilter, Set}; use sea_orm::{ActiveModelTrait, ColumnTrait, EntityTrait, QueryFilter, Set};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_json::to_string;
use time::OffsetDateTime; use time::OffsetDateTime;
use url::Url; use url::Url;
@ -22,7 +23,7 @@ use crate::{
}; };
use super::{ use super::{
objects::{CategoryType, ContentEntry, ContentFormat, Note, PublicKey}, objects::{CategoryType, ContentEntry, ContentFormat, Note, PublicKey, UserCollections},
superx::request_client, superx::request_client,
}; };
@ -43,12 +44,12 @@ pub async fn versia_post_from_db(
.one(DB.get().unwrap()) .one(DB.get().unwrap())
.await?; .await?;
let author = Url::parse(&creator.unwrap().url)?; let author = Url::parse(&creator.unwrap().url)?;
let visibility = match post.visibility.as_str() { let group = match post.visibility.as_str() {
"public" => super::objects::VisibilityType::Public, "public" => Some("public".to_string()),
"followers" => super::objects::VisibilityType::Followers, "followers" => Some("followers".to_string()),
"direct" => super::objects::VisibilityType::Direct, "direct" => None,
"unlisted" => super::objects::VisibilityType::Unlisted, //"unlisted" => super::objects::VisibilityType::Unlisted,
_ => super::objects::VisibilityType::Public, _ => Some("public".to_string()),
}; };
//let mut mentions = Vec::new(); //let mut mentions = Vec::new();
//for obj in post.tag.clone() { //for obj in post.tag.clone() {
@ -60,7 +61,7 @@ pub async fn versia_post_from_db(
ContentEntry::from_string(post.content), ContentEntry::from_string(post.content),
); );
let note = super::objects::Note { let note = super::objects::Note {
rtype: super::objects::VersiaType::Note, rtype: "Note".to_string(),
id: uuid::Uuid::parse_str(&post.id)?, id: uuid::Uuid::parse_str(&post.id)?,
author: author.clone(), author: author.clone(),
uri: url.clone(), uri: url.clone(),
@ -69,11 +70,10 @@ pub async fn versia_post_from_db(
mentions: None, mentions: None,
category: Some(CategoryType::Microblog), category: Some(CategoryType::Microblog),
device: None, device: None,
visibility: Some(visibility),
previews: None, previews: None,
replies_to: None, replies_to: None,
quotes: None, quotes: None,
group: None, group,
attachments: None, attachments: None,
subject: post.title, subject: post.title,
is_sensitive: Some(post.sensitive), is_sensitive: Some(post.sensitive),
@ -190,11 +190,9 @@ pub async fn versia_user_from_db(
content_type_header.unwrap().to_str().unwrap().to_string() content_type_header.unwrap().to_str().unwrap().to_string()
}); });
content_format.x.insert(media_type, content_entry); content_format.x.insert(media_type, content_entry);
let mut name = tag.name.chars(); let name = tag.name;
name.next();
name.next_back();
emojis.push(super::objects::CustomEmoji { emojis.push(super::objects::CustomEmoji {
name: name.as_str().to_string(), name,
url: content_format, url: content_format,
}); });
} }
@ -205,20 +203,23 @@ pub async fn versia_user_from_db(
let extensions = super::objects::ExtensionSpecs { let extensions = super::objects::ExtensionSpecs {
custom_emojis: emojis, custom_emojis: emojis,
}; };
let collections = UserCollections {
outbox: outbox_url,
followers: followers_url,
following: following_url,
featured: featured_url,
};
let user = super::objects::User { let user = super::objects::User {
rtype: super::objects::VersiaType::User, rtype: "User".to_string(),
id: uuid::Uuid::parse_str(&user.id)?, id: uuid::Uuid::parse_str(&user.id)?,
uri: url.clone(), uri: url.clone(),
username: user.username, username: user.username,
display_name, display_name,
inbox: inbox_url, inbox: inbox_url,
outbox: outbox_url,
followers: followers_url,
following: following_url,
featured: featured_url,
likes: likes_url, likes: likes_url,
dislikes: dislikes_url, dislikes: dislikes_url,
bio: Some(bio), bio: Some(bio),
collections,
avatar, avatar,
header, header,
fields: Some(fields), fields: Some(fields),
@ -226,10 +227,12 @@ pub async fn versia_user_from_db(
created_at: OffsetDateTime::from_unix_timestamp(user.created_at.timestamp()).unwrap(), created_at: OffsetDateTime::from_unix_timestamp(user.created_at.timestamp()).unwrap(),
public_key: PublicKey { public_key: PublicKey {
actor: url.clone(), actor: url.clone(),
public_key: "AAAAC3NzaC1lZDI1NTE5AAAAIMxsX+lEWkHZt9NOvn9yYFP0Z++186LY4b97C4mwj/f2" key: "AAAAC3NzaC1lZDI1NTE5AAAAIMxsX+lEWkHZt9NOvn9yYFP0Z++186LY4b97C4mwj/f2"
.to_string(), // dummy key .to_string(), // dummy key
algorithm: "ed25519".to_string(),
}, },
extensions: Some(extensions), extensions: Some(extensions),
manually_approves_followers: false,
}; };
Ok(user) Ok(user)
} }
@ -418,8 +421,8 @@ pub async fn db_user_from_url(url: Url) -> anyhow::Result<entities::user::Model>
), ),
summary: Set(option_content_format_text(ls_user.bio).await), summary: Set(option_content_format_text(ls_user.bio).await),
updated_at: Set(Some(Utc::now())), updated_at: Set(Some(Utc::now())),
followers: Set(Some(ls_user.followers.to_string())), followers: Set(Some(ls_user.collections.followers.to_string())),
following: Set(Some(ls_user.following.to_string())), following: Set(Some(ls_user.collections.following.to_string())),
ap_json: Set(Some(serde_json::to_string(&ap_json).unwrap())), ap_json: Set(Some(serde_json::to_string(&ap_json).unwrap())),
..Default::default() ..Default::default()
}; };
@ -464,33 +467,33 @@ pub async fn receive_versia_note(
mentions.push(obj.href.clone()); mentions.push(obj.href.clone());
} }
let to = match note let to = match note
.visibility .group
.clone() .clone()
.unwrap_or(super::objects::VisibilityType::Public) .unwrap_or("nothing".to_string()).as_str()
{ {
super::objects::VisibilityType::Public => { "public" => {
let mut vec = vec![public(), Url::parse(&user.followers.to_string().as_str())?]; let mut vec = vec![public(), Url::parse(&user.collections.followers.to_string().as_str())?];
vec.append(&mut mentions.clone()); vec.append(&mut mentions.clone());
vec vec
} }
super::objects::VisibilityType::Followers => { "unlisted" => {
let mut vec = vec![Url::parse(&user.followers.to_string().as_str())?]; let mut vec = vec![Url::parse(&user.collections.followers.to_string().as_str())?];
vec.append(&mut mentions.clone()); vec.append(&mut mentions.clone());
vec vec
} }
super::objects::VisibilityType::Direct => mentions.clone(), "followers" => {
super::objects::VisibilityType::Unlisted => { let mut vec = vec![Url::parse(&user.collections.followers.to_string().as_str())?];
let mut vec = vec![Url::parse(&user.followers.to_string().as_str())?];
vec.append(&mut mentions.clone()); vec.append(&mut mentions.clone());
vec vec
} }
_ => mentions.clone(),
}; };
let cc = match note let cc = match note
.visibility .group
.clone() .clone()
.unwrap_or(super::objects::VisibilityType::Public) .unwrap_or("nothing".to_string()).as_str()
{ {
super::objects::VisibilityType::Unlisted => Some(vec![public()]), "unlisted" => Some(vec![public()]),
_ => None, _ => None,
}; };
let reply: Option<ObjectId<entities::post::Model>> = let reply: Option<ObjectId<entities::post::Model>> =
@ -542,14 +545,14 @@ pub async fn receive_versia_note(
}; };
let visibility = match note let visibility = match note
.visibility .group
.clone() .clone()
.unwrap_or(super::objects::VisibilityType::Public) .unwrap_or("nothing".to_string()).as_str()
{ {
super::objects::VisibilityType::Public => "public", "public" => "public",
super::objects::VisibilityType::Followers => "followers", "followers" => "followers",
super::objects::VisibilityType::Direct => "direct", "unlisted" => "unlisted",
super::objects::VisibilityType::Unlisted => "unlisted", _ => "direct",
}; };
if let Some(obj) = note.replies_to { if let Some(obj) = note.replies_to {
println!("Quoting: {}", db_post_from_url(obj).await?.url); println!("Quoting: {}", db_post_from_url(obj).await?.url);

View file

@ -37,7 +37,7 @@ pub async fn send_follow_accept_to_versia(model: follow_relation::Model) -> anyh
let versia_followee = versia_user_from_db(followee_model).await?; let versia_followee = versia_user_from_db(followee_model).await?;
let entity = FollowResult { let entity = FollowResult {
rtype: super::objects::VersiaType::FollowAccept, rtype: "FollowAccept".to_string(),
id, id,
uri, uri,
created_at: OffsetDateTime::now_utc(), created_at: OffsetDateTime::now_utc(),

View file

@ -21,7 +21,6 @@ use url::Url;
use super::{ use super::{
conversion::versia_user_from_db, conversion::versia_user_from_db,
http::{versia_url_to_user, versia_url_to_user_and_model}, http::{versia_url_to_user, versia_url_to_user_and_model},
objects::VersiaType,
}; };
pub async fn inbox_entry(json: &str) -> Result<()> { pub async fn inbox_entry(json: &str) -> Result<()> {
@ -35,9 +34,6 @@ pub async fn inbox_entry(json: &str) -> Result<()> {
Some("Note") => { Some("Note") => {
let note: super::objects::Note = serde_json::from_str(json)?; let note: super::objects::Note = serde_json::from_str(json)?;
} }
Some("Patch") => {
let patch: super::objects::Patch = serde_json::from_str(json)?;
}
Some("Follow") => { Some("Follow") => {
let follow_req: super::objects::Follow = serde_json::from_str(json)?; let follow_req: super::objects::Follow = serde_json::from_str(json)?;
follow_request(follow_req).await?; follow_request(follow_req).await?;
@ -48,6 +44,9 @@ pub async fn inbox_entry(json: &str) -> Result<()> {
Some("FollowReject") => { Some("FollowReject") => {
let follow_rej: super::objects::FollowResult = serde_json::from_str(json)?; let follow_rej: super::objects::FollowResult = serde_json::from_str(json)?;
} }
Some("Unfollow") => {
let unfollow: super::objects::Unfollow = serde_json::from_str(json)?;
}
// Add more cases for other types as needed // Add more cases for other types as needed
_ => { _ => {
return Err(anyhow::anyhow!( return Err(anyhow::anyhow!(

View file

@ -35,21 +35,6 @@ fn sort_alphabetically<T: Serialize, S: serde::Serializer>(
#[derive(Serialize)] #[derive(Serialize)]
pub struct SortAlphabetically<T: Serialize>(#[serde(serialize_with = "sort_alphabetically")] pub T); pub struct SortAlphabetically<T: Serialize>(#[serde(serialize_with = "sort_alphabetically")] pub T);
#[derive(Debug, Serialize, Deserialize, Clone)]
pub enum VersiaType {
User,
Note,
Patch,
Like,
Dislike,
Follow,
FollowAccept,
FollowReject,
Undo,
Extension,
ServerMetadata,
}
#[derive(Debug, Serialize, Deserialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone)]
pub enum CategoryType { pub enum CategoryType {
Microblog, Microblog,
@ -61,19 +46,10 @@ pub enum CategoryType {
Messaging, Messaging,
} }
#[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(rename_all = "snake_case")]
pub enum VisibilityType {
Public,
Unlisted,
Followers,
Direct,
}
#[derive(Debug, Serialize, Deserialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone)]
pub enum VersiaExtensions { pub enum VersiaExtensions {
#[serde(rename = "pub.versia:microblogging/Announce")] #[serde(rename = "pub.versia:share/Share")]
Announce, Share,
#[serde(rename = "pub.versia:custom_emojis")] #[serde(rename = "pub.versia:custom_emojis")]
CustomEmojis, CustomEmojis,
#[serde(rename = "pub.versia:reactions/Reaction")] #[serde(rename = "pub.versia:reactions/Reaction")]
@ -96,8 +72,9 @@ pub enum VersiaExtensions {
#[derive(Debug, Serialize, Deserialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone)]
pub struct PublicKey { pub struct PublicKey {
pub public_key: String, pub key: String,
pub actor: Url, pub actor: Url,
pub algorithm: String,
} }
#[derive(Debug, Serialize, Deserialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone)]
@ -217,6 +194,7 @@ pub struct FieldKV {
#[derive(Debug, Serialize, Deserialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone)]
pub struct ContentEntry { pub struct ContentEntry {
content: String, content: String,
remote: bool,
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
description: Option<String>, description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
@ -238,6 +216,7 @@ impl ContentEntry {
pub fn from_string(string: String) -> ContentEntry { pub fn from_string(string: String) -> ContentEntry {
ContentEntry { ContentEntry {
content: string, content: string,
remote: false,
description: None, description: None,
size: None, size: None,
hash: None, hash: None,
@ -254,18 +233,15 @@ impl ContentEntry {
pub struct User { pub struct User {
pub public_key: PublicKey, pub public_key: PublicKey,
#[serde(rename = "type")] #[serde(rename = "type")]
pub rtype: VersiaType, pub rtype: String,
pub id: Uuid, pub id: Uuid,
pub uri: Url, pub uri: Url,
#[serde(with = "iso_versia")] #[serde(with = "iso_versia")]
pub created_at: OffsetDateTime, pub created_at: OffsetDateTime,
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub display_name: Option<String>, pub display_name: Option<String>,
pub collections: UserCollections,
pub inbox: Url, pub inbox: Url,
pub outbox: Url,
pub featured: Url,
pub followers: Url,
pub following: Url,
pub likes: Url, pub likes: Url,
pub dislikes: Url, pub dislikes: Url,
pub username: String, pub username: String,
@ -280,6 +256,15 @@ pub struct User {
pub indexable: bool, pub indexable: bool,
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub extensions: Option<ExtensionSpecs>, pub extensions: Option<ExtensionSpecs>,
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,
} }
#[derive(Debug, Serialize, Deserialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone)]
@ -321,7 +306,7 @@ pub struct LinkPreview {
#[derive(Debug, Serialize, Deserialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Note { pub struct Note {
#[serde(rename = "type")] #[serde(rename = "type")]
pub rtype: VersiaType, pub rtype: String,
pub id: Uuid, pub id: Uuid,
pub uri: Url, pub uri: Url,
pub author: Url, pub author: Url,
@ -349,46 +334,6 @@ pub struct Note {
pub subject: Option<String>, pub subject: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub is_sensitive: Option<bool>, pub is_sensitive: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub visibility: Option<VisibilityType>,
//TODO extensions
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Patch {
#[serde(rename = "type")]
pub rtype: VersiaType,
pub id: Uuid,
pub uri: Url,
pub author: Url,
#[serde(with = "iso_versia")]
pub created_at: OffsetDateTime,
#[serde(with = "iso_versia")]
pub patched_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>,
#[serde(skip_serializing_if = "Option::is_none")]
pub visibility: Option<VisibilityType>,
//TODO extensions //TODO extensions
} }
@ -399,14 +344,14 @@ pub struct Outbox {
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub next: Option<Url>, pub next: Option<Url>,
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub prev: Option<Url>, pub previous: Option<Url>,
pub items: Vec<Note>, pub items: Vec<Note>,
} }
#[derive(Debug, Serialize, Deserialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Follow { pub struct Follow {
#[serde(rename = "type")] #[serde(rename = "type")]
pub rtype: VersiaType, pub rtype: String,
pub id: Uuid, pub id: Uuid,
pub uri: Url, pub uri: Url,
pub author: Url, pub author: Url,
@ -418,7 +363,7 @@ pub struct Follow {
#[derive(Debug, Serialize, Deserialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone)]
pub struct FollowResult { pub struct FollowResult {
#[serde(rename = "type")] #[serde(rename = "type")]
pub rtype: VersiaType, pub rtype: String,
pub id: Uuid, pub id: Uuid,
pub uri: Url, pub uri: Url,
pub author: Url, pub author: Url,
@ -426,3 +371,26 @@ pub struct FollowResult {
pub created_at: OffsetDateTime, pub created_at: OffsetDateTime,
pub follower: Url, pub follower: Url,
} }
#[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,
}

View file

@ -10,13 +10,13 @@ pub async fn serialize_user(user: super::objects::User) -> anyhow::Result<String
Ok(data) Ok(data)
} }
pub async fn deserialize_versia_type(data: String) -> anyhow::Result<super::objects::VersiaType> { pub async fn deserialize_versia_type(data: String) -> anyhow::Result<String> {
let versia_type: super::objects::VersiaType = serde_json::from_str(&data)?; let versia_type: String = serde_json::from_str(&data)?;
Ok(versia_type) Ok(versia_type)
} }
pub async fn serialize_versia_type( pub async fn serialize_versia_type(
versia_type: super::objects::VersiaType, versia_type: String,
) -> anyhow::Result<String> { ) -> anyhow::Result<String> {
let data = serde_json::to_string(&versia_type)?; let data = serde_json::to_string(&versia_type)?;
Ok(data) Ok(data)

View file

@ -13,7 +13,7 @@ async fn test_user_serial() {
let user = super::superx::deserialize_user(response.text().await.unwrap()) let user = super::superx::deserialize_user(response.text().await.unwrap())
.await .await
.unwrap(); .unwrap();
let response_outbox = client.get(user.outbox.as_str()).send().await.unwrap(); let response_outbox = client.get(user.collections.outbox.as_str()).send().await.unwrap();
let outbox = super::superx::deserialize_outbox(response_outbox.text().await.unwrap()) let outbox = super::superx::deserialize_outbox(response_outbox.text().await.unwrap())
.await .await
.unwrap(); .unwrap();
@ -40,7 +40,7 @@ pub async fn main() -> anyhow::Result<()> {
let user_json = serde_json::to_string_pretty(&SortAlphabetically(&user))?; let user_json = serde_json::to_string_pretty(&SortAlphabetically(&user))?;
println!("{}", user_json); println!("{}", user_json);
let response_outbox = client.get(user.outbox.as_str()).send().await?; let response_outbox = client.get(user.collections.outbox.as_str()).send().await?;
let outbox_json = response_outbox.text().await?; let outbox_json = response_outbox.text().await?;
let outbox = super::superx::deserialize_outbox(outbox_json).await?; let outbox = super::superx::deserialize_outbox(outbox_json).await?;