merge in old new type defs

This commit is contained in:
emilis 2022-12-17 18:53:58 +00:00
parent de12258368
commit 5473512787
2 changed files with 246 additions and 105 deletions

View File

@ -1,24 +1,63 @@
use async_trait::async_trait; use std::collections::HashMap;
use flabk_derive::IRI;
use flabk_derive::{Resolvable, IRI};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use self::{ use self::{
context::Context, context::APContext,
note::Note,
resolve::ResolveError, resolve::ResolveError,
serde_ext::{expand_partial, pull_single_into_vec}, serde_ext::{expand_partial, into_vec},
}; };
pub mod context; pub mod context;
pub mod note;
pub mod resolve; pub mod resolve;
mod serde_ext; mod serde_ext;
#[derive(Clone, Copy, Serialize, Deserialize, Debug)] #[derive(Clone, Copy, Serialize, Deserialize, Debug)]
pub enum ActivityKind { pub enum ObjectKind {
Create, Article,
Like, Audio,
Document,
Event,
Image,
Note, Note,
Page,
Place,
Profile,
Relationship,
Tombstone,
Video,
}
#[derive(Clone, Copy, Serialize, Deserialize, Debug)]
pub enum ActivityKind {
Accept,
Add,
Announce,
Arrive,
Block,
Create,
Delete,
Dislike,
Flag,
Follow,
Invite,
Join,
Leave,
Like,
Listen,
Move,
Offer,
Question,
Reject,
Read,
Remove,
TentativeReject,
TentativeAccept,
Travel,
Undo,
Update,
View,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -35,45 +74,211 @@ impl From<ResolveError> for ExpandError {
} }
} }
#[async_trait] /// A Collection is a subtype of Object that
pub trait ExpandLD<T> { /// represents ordered or unordered sets of
async fn expand(obj: &ObjectLD) -> Result<T, ExpandError>; /// Object or Link instances.
} #[derive(Debug, Clone, Deserialize)]
pub struct Collection<T> {
#[derive(Clone, Serialize, Deserialize)] pub summary: Option<String>,
pub struct ActivityLD { #[serde(rename = "type")]
#[serde(rename = "@context")] pub kind: String,
pub context_uri: String, #[serde(rename = "totalItems")]
pub kind: ActivityKind, pub total_items: Vec<T>,
#[serde(rename = "actor")]
pub actor_uri: String,
#[serde(rename = "to")]
pub to_uris: Vec<String>,
pub object: Option<ObjectLD>,
} }
#[derive(Debug, Clone, Deserialize)] #[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")] pub struct Attachment {
pub struct Activity {
// #[serde(rename = "@context")]
// #[serde(deserialize_with = "expand_partial")]
// pub ap_context: Context,
pub id: String,
#[serde(rename = "type")] #[serde(rename = "type")]
pub kind: ActivityKind, pub kind: String,
#[serde(deserialize_with = "expand_partial")]
pub attributed_to: Actor,
pub content: Option<String>, pub content: Option<String>,
pub context: Option<String>, pub url: String,
#[serde(deserialize_with = "pull_single_into_vec")]
pub to: Vec<String>,
pub url: Option<String>,
} }
#[derive(Clone, Serialize, Deserialize, Debug)] // TODO: maybe this can work as attachment w/ the ID being more like
pub struct ObjectLD { // the LD IDs?
#[derive(Debug, Clone, Deserialize)]
pub struct Image {
#[serde(flatten)]
pub base: ObjectBase,
#[serde(rename = "type")]
pub kind: Option<ObjectKind>,
pub id: String,
#[serde(deserialize_with = "into_vec")]
pub url: Vec<Link>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct Audience {
#[serde(rename = "type")]
pub kind: String,
pub name: String,
}
#[derive(Clone, Copy, Debug, Deserialize)]
pub enum Unit {
#[serde(rename = "m")]
Meters,
}
#[derive(Debug, Clone, Deserialize)]
pub struct Location {
#[serde(rename = "type")]
pub kind: String,
pub name: String,
pub longitude: Option<f64>,
pub latitude: Option<f64>,
pub altitude: Option<f64>,
pub units: Unit,
}
#[derive(Debug, Clone, Deserialize)]
pub struct Preview {
#[serde(rename = "type")]
pub kind: String,
pub name: String,
pub duration: Option<String>,
pub url: Link,
}
#[derive(Debug, Clone, Deserialize)]
pub struct APResult {
#[serde(rename = "type")]
pub kind: String,
pub name: String,
}
/// ObjectBase contains base Activity Streams
/// members that all objects should have. Except kind.
///
/// This object is intended to be used by inlining it into
/// other serializable/deserializable objects.
#[derive(Debug, Clone, Deserialize, Default)]
#[serde(rename_all = "camelCase")]
pub struct ObjectBase {
#[serde(rename = "@context")] #[serde(rename = "@context")]
pub context_uri: Option<String>, #[serde(deserialize_with = "expand_partial")]
pub ap_context: APContext,
pub name: Option<String>,
pub name_map: Option<HashMap<String, String>>,
#[serde(deserialize_with = "into_vec")]
pub attachment: Vec<Attachment>,
#[serde(deserialize_with = "into_vec")]
pub attributed_to: Vec<Actor>,
pub audience: Option<Audience>,
pub media_type: Option<String>,
pub content: Option<String>,
pub content_map: Option<HashMap<String, String>>,
pub context: Option<String>,
pub start_time: Option<String>,
pub end_time: Option<String>,
pub generator: Option<Actor>,
#[serde(deserialize_with = "into_vec")]
pub icon: Vec<Link>,
// omit in_reply_to
pub location: Option<Location>,
pub preview: Option<Preview>,
pub published: Option<String>,
pub updated: Option<String>,
pub replies: Option<Collection<()>>, // TODO: type
pub summary: Option<String>,
pub summary_map: Option<HashMap<String, String>>,
#[serde(deserialize_with = "into_vec")]
pub tag: Vec<Actor>,
// omit url for now: need to merge into_vec & expand_partial
#[serde(deserialize_with = "into_vec")]
pub to: Vec<String>,
#[serde(deserialize_with = "into_vec")]
pub bto: Vec<String>,
#[serde(deserialize_with = "into_vec")]
pub cc: Vec<String>,
#[serde(deserialize_with = "into_vec")]
pub bcc: Vec<String>,
pub duration: Option<String>,
}
#[derive(Debug, Clone, Deserialize, Resolvable, IRI, Default)]
pub struct Object {
#[serde(flatten)]
pub base: ObjectBase,
#[serde(rename = "type")]
pub kind: Option<ObjectKind>,
pub id: String,
}
#[derive(Debug, Clone, Deserialize)]
pub struct Link {
#[serde(rename = "type")]
pub kind: Option<ActivityKind>,
pub name: Option<String>,
pub href: String,
#[serde(rename = "hreflang")]
pub href_lang: Option<String>,
#[serde(rename = "mediaType")]
pub media_type: Option<String>,
pub height: u32,
pub width: u32,
}
/// An Activity is a subtype of Object that describes
/// some form of action that may happen,
/// is currently happening, or has already happened.
///
/// The Activity type itself serves as an abstract base type
/// for all types of activities.
/// It is important to note that the Activity type itself
/// does not carry any specific semantics about the kind of action being taken.
#[derive(Debug, Clone, Deserialize, Resolvable)]
#[serde(rename_all = "camelCase")]
pub struct Activity {
#[serde(flatten)]
pub base: ObjectBase,
#[serde(rename = "type")]
pub kind: Option<ActivityKind>,
pub id: String,
#[serde(deserialize_with = "expand_partial")]
pub actor: Option<Actor>,
#[serde(deserialize_with = "expand_partial")]
pub object: Option<Object>,
pub result: Option<APResult>,
pub target: Option<Basic>,
pub origin: Option<Basic>,
pub instrument: Option<Basic>,
}
/// Instances of IntransitiveActivity are a subtype of Activity
/// representing intransitive actions.
#[derive(Debug, Clone, Deserialize, Resolvable)]
#[serde(rename_all = "camelCase")]
pub struct IntransitiveActivity {
#[serde(flatten)]
pub base: ObjectBase,
#[serde(rename = "type")]
pub kind: Option<ActivityKind>,
pub id: String,
#[serde(deserialize_with = "expand_partial")]
pub actor: Option<Actor>,
pub result: Option<APResult>,
pub target: Option<Basic>,
pub origin: Option<Basic>,
pub instrument: Option<Basic>,
}
pub enum ActorType {
Application,
Group,
Organization,
Person,
Service,
}
#[derive(Debug, Clone, Deserialize)]
pub struct Basic {
#[serde(rename = "type")]
pub kind: Option<ActivityKind>,
pub name: Option<String>,
}
#[derive(Debug, Clone, Deserialize, IRI, Default, Resolvable)]
pub struct Actor {
pub id: String, pub id: String,
#[serde(rename = "type")] #[serde(rename = "type")]
pub kind: Option<ActivityKind>, pub kind: Option<ActivityKind>,
@ -117,7 +322,7 @@ pub async fn test() {
"url": "https://localhost/u/test/h/6Q8BFF8W6PZT2ddngZ" "url": "https://localhost/u/test/h/6Q8BFF8W6PZT2ddngZ"
}"#; }"#;
let obj = serde_json::from_str::<Activity>(obj).unwrap(); let obj = serde_json::from_str::<Object>(obj).unwrap();
println!(); println!();
println!("{:#?}", obj); println!("{:#?}", obj);
} }

View File

@ -1,64 +0,0 @@
use async_trait::async_trait;
use super::{
context::{self, Context},
resolve, ActivityKind, Actor, ExpandError, ExpandLD, ObjectLD,
};
#[derive(Debug, Clone)]
pub struct Note {
pub id: String,
pub content: Option<String>,
pub context: Option<String>,
pub published_at: Option<String>,
pub author: Actor,
pub to: Vec<Actor>,
pub url: Option<String>,
pub conversation: Option<String>,
}
#[async_trait]
impl ExpandLD<Note> for Note {
async fn expand(obj: &ObjectLD) -> Result<Note, ExpandError> {
let obj = obj.clone();
let resolver = resolve::Resolver::new();
if let Some(kind) = obj.kind {
if let ActivityKind::Note = kind {
Ok(Note {
id: obj.id,
content: obj.content,
published_at: obj.published,
author: obj
.attributed_to
.map(|id| Actor { id })
.ok_or(ExpandError::NoAttribution)?,
to: obj.to_uris.into_iter().map(|id| Actor { id }).collect(),
url: obj.url,
context: obj.context,
conversation: obj.conversation,
})
} else {
Err(ExpandError::InvalidKind(Some(kind)))
}
} else {
Err(ExpandError::InvalidKind(None))
}
}
}
impl Into<ObjectLD> for Note {
fn into(self) -> ObjectLD {
ObjectLD {
context_uri: Some(context::CONTEXT_ID.to_string()),
id: self.id.clone(),
kind: Some(ActivityKind::Note),
attributed_to: Some(self.author.id),
published: self.published_at,
content: self.content,
context: self.context,
conversation: self.conversation,
url: Some(self.id),
to_uris: self.to.into_iter().map(|a| a.id).collect(),
}
}
}