feat: extended database entities
This commit is contained in:
parent
efc9c79ab0
commit
30637f93ee
5 changed files with 314 additions and 64 deletions
|
@ -18,7 +18,19 @@ impl MigrationTrait for Migration {
|
|||
.primary_key()
|
||||
)
|
||||
.col(ColumnDef::new(Users::ActorType).string().not_null())
|
||||
.col(ColumnDef::new(Users::Domain).string().not_null())
|
||||
.col(ColumnDef::new(Users::Name).string().not_null())
|
||||
.col(ColumnDef::new(Users::Summary).string().null())
|
||||
.col(ColumnDef::new(Users::Image).string().null())
|
||||
.col(ColumnDef::new(Users::Icon).string().null())
|
||||
.col(ColumnDef::new(Users::PreferredUsername).string().null())
|
||||
.col(ColumnDef::new(Users::Inbox).string().null())
|
||||
.col(ColumnDef::new(Users::SharedInbox).string().null())
|
||||
.col(ColumnDef::new(Users::Outbox).string().null())
|
||||
.col(ColumnDef::new(Users::Following).string().null())
|
||||
.col(ColumnDef::new(Users::Followers).string().null())
|
||||
.col(ColumnDef::new(Users::Created).date_time().not_null())
|
||||
.col(ColumnDef::new(Users::Updated).date_time().not_null())
|
||||
.to_owned()
|
||||
)
|
||||
.await?;
|
||||
|
@ -38,7 +50,11 @@ impl MigrationTrait for Migration {
|
|||
.col(ColumnDef::new(Activities::Actor).string().not_null())
|
||||
.col(ColumnDef::new(Activities::Object).string().null())
|
||||
.col(ColumnDef::new(Activities::Target).string().null())
|
||||
.col(ColumnDef::new(Activities::Published).string().null())
|
||||
.col(ColumnDef::new(Activities::To).json().null())
|
||||
.col(ColumnDef::new(Activities::Bto).json().null())
|
||||
.col(ColumnDef::new(Activities::Cc).json().null())
|
||||
.col(ColumnDef::new(Activities::Bcc).json().null())
|
||||
.col(ColumnDef::new(Activities::Published).date_time().not_null())
|
||||
.to_owned()
|
||||
).await?;
|
||||
|
||||
|
@ -58,7 +74,7 @@ impl MigrationTrait for Migration {
|
|||
.col(ColumnDef::new(Objects::Name).string().null())
|
||||
.col(ColumnDef::new(Objects::Summary).string().null())
|
||||
.col(ColumnDef::new(Objects::Content).string().null())
|
||||
.col(ColumnDef::new(Objects::Published).string().null())
|
||||
.col(ColumnDef::new(Objects::Published).string().not_null())
|
||||
.to_owned()
|
||||
).await?;
|
||||
|
||||
|
@ -86,8 +102,20 @@ impl MigrationTrait for Migration {
|
|||
enum Users {
|
||||
Table,
|
||||
Id,
|
||||
Domain,
|
||||
ActorType,
|
||||
Name,
|
||||
Summary,
|
||||
Image,
|
||||
Icon,
|
||||
PreferredUsername,
|
||||
Inbox,
|
||||
SharedInbox,
|
||||
Outbox,
|
||||
Following,
|
||||
Followers,
|
||||
Created,
|
||||
Updated,
|
||||
}
|
||||
|
||||
#[derive(DeriveIden)]
|
||||
|
@ -98,7 +126,11 @@ enum Activities {
|
|||
Actor,
|
||||
Object,
|
||||
Target,
|
||||
Published
|
||||
Cc,
|
||||
Bcc,
|
||||
To,
|
||||
Bto,
|
||||
Published,
|
||||
}
|
||||
|
||||
#[derive(DeriveIden)]
|
||||
|
@ -106,9 +138,9 @@ enum Objects {
|
|||
Table,
|
||||
Id,
|
||||
ObjectType,
|
||||
AttributedTo,
|
||||
Name,
|
||||
Summary,
|
||||
AttributedTo,
|
||||
Content,
|
||||
Published,
|
||||
}
|
||||
|
|
|
@ -1,6 +1,22 @@
|
|||
use sea_orm::entity::prelude::*;
|
||||
use sea_orm::{entity::prelude::*, FromJsonQueryResult};
|
||||
|
||||
use crate::activitystream::{Node, macros::InsertValue, object::{activity::{Activity, ActivityType}, actor::Actor, Object, ObjectType}, Base, BaseType};
|
||||
use crate::activitystream::{self, link::Link, object::{activity::{Activity, ActivityMut, ActivityType}, actor::Actor, Object, ObjectMut, ObjectType}, Base, BaseMut, BaseType, Node};
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize, FromJsonQueryResult)]
|
||||
pub struct Audience(pub Vec<String>);
|
||||
|
||||
impl<T : Link> From<Node<T>> for Audience {
|
||||
fn from(value: Node<T>) -> Self {
|
||||
Audience(
|
||||
match value {
|
||||
Node::Empty => vec![],
|
||||
Node::Link(l) => vec![l.href().to_string()],
|
||||
Node::Object(o) => if let Some(id) = o.id() { vec![id.to_string()] } else { vec![] },
|
||||
Node::Array(arr) => arr.into_iter().filter_map(|l| Some(l.id()?.to_string())).collect(),
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
||||
#[sea_orm(table_name = "activities")]
|
||||
|
@ -12,14 +28,45 @@ pub struct Model {
|
|||
pub activity_type: ActivityType,
|
||||
pub actor: String, // TODO relates to USER
|
||||
pub object: Option<String>, // TODO relates to NOTES maybe????? maybe other tables??????
|
||||
|
||||
pub target: Option<String>, // TODO relates to USER maybe??
|
||||
pub cc: Audience,
|
||||
pub bcc: Audience,
|
||||
pub to: Audience,
|
||||
pub bto: Audience,
|
||||
pub published: ChronoDateTimeUtc,
|
||||
|
||||
// TODO: origin, result, instrument
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||
pub enum Relation {}
|
||||
pub enum Relation {
|
||||
#[sea_orm(
|
||||
belongs_to = "super::user::Entity",
|
||||
from = "Column::Actor",
|
||||
to = "super::user::Column::Id"
|
||||
)]
|
||||
User,
|
||||
|
||||
#[sea_orm(
|
||||
belongs_to = "super::object::Entity",
|
||||
from = "Column::Object",
|
||||
to = "super::object::Column::Id"
|
||||
)]
|
||||
Object,
|
||||
}
|
||||
|
||||
impl Related<super::user::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::User.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl Related<super::object::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::Object.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
|
||||
|
@ -33,21 +80,44 @@ impl Base for Model {
|
|||
}
|
||||
|
||||
fn underlying_json_object(self) -> serde_json::Value {
|
||||
let mut map = serde_json::Map::new();
|
||||
map.insert_str("id", Some(&self.id));
|
||||
map.insert_str("type", Some(self.activity_type.as_ref()));
|
||||
map.insert_str("actor", Some(&self.actor));
|
||||
map.insert_str("object", self.object.as_deref());
|
||||
map.insert_str("target", self.target.as_deref());
|
||||
map.insert_timestr("published", Some(self.published));
|
||||
serde_json::Value::Object(map)
|
||||
activitystream::object()
|
||||
.set_id(Some(&self.id))
|
||||
.set_activity_type(Some(self.activity_type))
|
||||
.set_actor(Node::link(self.actor))
|
||||
.set_object(Node::maybe_link(self.object))
|
||||
.set_target(Node::maybe_link(self.target))
|
||||
.set_published(Some(self.published))
|
||||
.set_to(Node::links(self.to.0.clone()))
|
||||
.set_bto(Node::empty())
|
||||
.set_cc(Node::links(self.cc.0.clone()))
|
||||
.set_bcc(Node::empty())
|
||||
}
|
||||
}
|
||||
|
||||
impl Object for Model {
|
||||
fn object_type(&self) -> Option<ObjectType> {
|
||||
Some(ObjectType::Activity(self.activity_type))
|
||||
}
|
||||
|
||||
fn published(&self) -> Option<chrono::DateTime<chrono::Utc>> {
|
||||
Some(self.published)
|
||||
}
|
||||
|
||||
fn to(&self) -> Node<impl Link> {
|
||||
Node::links(self.to.0.clone())
|
||||
}
|
||||
|
||||
fn bto(&self) -> Node<impl Link> {
|
||||
Node::links(self.bto.0.clone())
|
||||
}
|
||||
|
||||
fn cc(&self) -> Node<impl Link> {
|
||||
Node::links(self.cc.0.clone())
|
||||
}
|
||||
|
||||
fn bcc(&self) -> Node<impl Link> {
|
||||
Node::links(self.bcc.0.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl Activity for Model {
|
||||
|
@ -83,6 +153,10 @@ impl Model {
|
|||
object: activity.object().id().map(|x| x.to_string()),
|
||||
target: activity.target().id().map(|x| x.to_string()),
|
||||
published: activity.published().ok_or(super::FieldError("published"))?,
|
||||
to: activity.to().into(),
|
||||
bto: activity.bto().into(),
|
||||
cc: activity.cc().into(),
|
||||
bcc: activity.bcc().into(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
use sea_orm::IntoActiveModel;
|
||||
|
||||
use crate::{activitypub::PUBLIC_TARGET, activitystream::object::actor::Actor, model::activity::Audience};
|
||||
|
||||
pub mod user;
|
||||
pub mod object;
|
||||
pub mod activity;
|
||||
|
@ -7,34 +11,52 @@ pub mod activity;
|
|||
pub struct FieldError(pub &'static str);
|
||||
|
||||
pub async fn faker(db: &sea_orm::DatabaseConnection, domain: String) -> Result<(), sea_orm::DbErr> {
|
||||
use sea_orm::EntityTrait;
|
||||
use sea_orm::{EntityTrait, Set};
|
||||
|
||||
user::Entity::insert(user::ActiveModel {
|
||||
id: sea_orm::Set(format!("{domain}/users/root")),
|
||||
name: sea_orm::Set("root".into()),
|
||||
actor_type: sea_orm::Set(super::activitystream::object::actor::ActorType::Person),
|
||||
}).exec(db).await?;
|
||||
let root = user::Model {
|
||||
id: format!("{domain}/users/root"),
|
||||
name: "root".into(),
|
||||
domain: crate::activitypub::domain(&domain),
|
||||
preferred_username: Some("Administrator".to_string()),
|
||||
summary: Some("hello world! i'm manually generated but served dynamically from db!".to_string()),
|
||||
following: None,
|
||||
followers: None,
|
||||
icon: Some("https://cdn.alemi.dev/social/circle-square.png".to_string()),
|
||||
image: Some("https://cdn.alemi.dev/social/someriver-xs.jpg".to_string()),
|
||||
inbox: None,
|
||||
shared_inbox: None,
|
||||
outbox: None,
|
||||
actor_type: super::activitystream::object::actor::ActorType::Person,
|
||||
created: chrono::Utc::now(),
|
||||
updated: chrono::Utc::now(),
|
||||
};
|
||||
|
||||
user::Entity::insert(root.clone().into_active_model()).exec(db).await?;
|
||||
|
||||
for i in (0..100).rev() {
|
||||
let oid = uuid::Uuid::new_v4();
|
||||
let aid = uuid::Uuid::new_v4();
|
||||
object::Entity::insert(object::ActiveModel {
|
||||
id: sea_orm::Set(format!("{domain}/objects/{oid}")),
|
||||
name: sea_orm::Set(None),
|
||||
object_type: sea_orm::Set(crate::activitystream::object::ObjectType::Note),
|
||||
attributed_to: sea_orm::Set(Some(format!("{domain}/users/root"))),
|
||||
summary: sea_orm::Set(None),
|
||||
content: sea_orm::Set(Some(format!("[{i}] Tic(k). Quasiparticle of intensive multiplicity. Tics (or ticks) are intrinsically several components of autonomously numbering anorganic populations, propagating by contagion between segmentary divisions in the order of nature. Ticks - as nonqualitative differentially-decomposable counting marks - each designate a multitude comprehended as a singular variation in tic(k)-density."))),
|
||||
published: sea_orm::Set(chrono::Utc::now() - std::time::Duration::from_secs(60*i)),
|
||||
id: Set(format!("{domain}/objects/{oid}")),
|
||||
name: Set(None),
|
||||
object_type: Set(crate::activitystream::object::ObjectType::Note),
|
||||
attributed_to: Set(Some(format!("{domain}/users/root"))),
|
||||
summary: Set(None),
|
||||
content: Set(Some(format!("[{i}] Tic(k). Quasiparticle of intensive multiplicity. Tics (or ticks) are intrinsically several components of autonomously numbering anorganic populations, propagating by contagion between segmentary divisions in the order of nature. Ticks - as nonqualitative differentially-decomposable counting marks - each designate a multitude comprehended as a singular variation in tic(k)-density."))),
|
||||
published: Set(chrono::Utc::now() - std::time::Duration::from_secs(60*i)),
|
||||
}).exec(db).await?;
|
||||
|
||||
activity::Entity::insert(activity::ActiveModel {
|
||||
id: sea_orm::Set(format!("{domain}/activities/{aid}")),
|
||||
activity_type: sea_orm::Set(crate::activitystream::object::activity::ActivityType::Create),
|
||||
actor: sea_orm::Set(format!("{domain}/users/root")),
|
||||
object: sea_orm::Set(Some(format!("{domain}/objects/{oid}"))),
|
||||
target: sea_orm::Set(None),
|
||||
published: sea_orm::Set(chrono::Utc::now() - std::time::Duration::from_secs(60*i)),
|
||||
id: Set(format!("{domain}/activities/{aid}")),
|
||||
activity_type: Set(crate::activitystream::object::activity::ActivityType::Create),
|
||||
actor: Set(format!("{domain}/users/root")),
|
||||
object: Set(Some(format!("{domain}/objects/{oid}"))),
|
||||
target: Set(None),
|
||||
published: Set(chrono::Utc::now() - std::time::Duration::from_secs(60*i)),
|
||||
to: Set(Audience(vec![PUBLIC_TARGET.to_string()])),
|
||||
bto: Set(Audience::default()),
|
||||
cc: Set(Audience(vec![root.followers().id().unwrap_or("").to_string()])),
|
||||
bcc: Set(Audience::default()),
|
||||
}).exec(db).await?;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use sea_orm::entity::prelude::*;
|
||||
use crate::activitystream::prelude::*;
|
||||
|
||||
use crate::activitystream::{macros::InsertValue, object::{actor::Actor, Object, ObjectType}, Base, BaseType, Node};
|
||||
use crate::activitystream::{object::ObjectType, BaseType, Node};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
||||
#[sea_orm(table_name = "objects")]
|
||||
|
@ -17,11 +18,33 @@ pub struct Model {
|
|||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||
pub enum Relation {}
|
||||
pub enum Relation {
|
||||
#[sea_orm(has_many = "super::activity::Entity")]
|
||||
Activity,
|
||||
|
||||
#[sea_orm(
|
||||
belongs_to = "super::user::Entity",
|
||||
from = "Column::AttributedTo",
|
||||
to = "super::user::Column::Id",
|
||||
)]
|
||||
User,
|
||||
}
|
||||
|
||||
impl Related<super::activity::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::Activity.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl Related<super::user::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::User.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
|
||||
impl Base for Model {
|
||||
impl crate::activitystream::Base for Model {
|
||||
fn id(&self) -> Option<&str> {
|
||||
Some(&self.id)
|
||||
}
|
||||
|
@ -31,24 +54,23 @@ impl Base for Model {
|
|||
}
|
||||
|
||||
fn underlying_json_object(self) -> serde_json::Value {
|
||||
let mut map = serde_json::Map::new();
|
||||
map.insert_str("id", Some(&self.id));
|
||||
map.insert_str("type", Some(self.object_type.as_ref()));
|
||||
map.insert_str("attributedTo", self.attributed_to.as_deref());
|
||||
map.insert_str("name", self.name.as_deref());
|
||||
map.insert_str("summary", self.summary.as_deref());
|
||||
map.insert_str("content", self.content.as_deref());
|
||||
map.insert_timestr("published", Some(self.published));
|
||||
serde_json::Value::Object(map)
|
||||
crate::activitystream::object()
|
||||
.set_id(Some(&self.id))
|
||||
.set_object_type(Some(self.object_type))
|
||||
.set_attributed_to(Node::maybe_link(self.attributed_to))
|
||||
.set_name(self.name.as_deref())
|
||||
.set_summary(self.summary.as_deref())
|
||||
.set_content(self.content.as_deref())
|
||||
.set_published(Some(self.published))
|
||||
}
|
||||
}
|
||||
|
||||
impl Object for Model {
|
||||
impl crate::activitystream::object::Object for Model {
|
||||
fn object_type(&self) -> Option<ObjectType> {
|
||||
Some(self.object_type)
|
||||
}
|
||||
|
||||
fn attributed_to(&self) -> Node<impl Actor> {
|
||||
fn attributed_to(&self) -> Node<impl crate::activitystream::object::actor::Actor> {
|
||||
Node::<serde_json::Value>::from(self.attributed_to.as_deref())
|
||||
}
|
||||
|
||||
|
@ -70,7 +92,7 @@ impl Object for Model {
|
|||
}
|
||||
|
||||
impl Model {
|
||||
pub fn new(object: &impl Object) -> Result<Self, super::FieldError> {
|
||||
pub fn new(object: &impl crate::activitystream::object::Object) -> Result<Self, super::FieldError> {
|
||||
Ok(Model {
|
||||
id: object.id().ok_or(super::FieldError("id"))?.to_string(),
|
||||
object_type: object.object_type().ok_or(super::FieldError("type"))?,
|
||||
|
|
|
@ -1,25 +1,63 @@
|
|||
use sea_orm::entity::prelude::*;
|
||||
use crate::activitystream::prelude::*;
|
||||
|
||||
use crate::activitystream::{macros::InsertValue, object::actor::{Actor, ActorType}, Base, BaseType, Object, ObjectType};
|
||||
use crate::{activitypub, activitystream::{object::actor::ActorType, BaseType, Node, ObjectType}};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
||||
#[sea_orm(table_name = "users")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key)]
|
||||
/// must be user@instance.org, even if local! TODO bad design...
|
||||
/// must be full AP ID, since they are unique over the network
|
||||
pub id: String,
|
||||
|
||||
pub domain: String,
|
||||
pub actor_type: ActorType,
|
||||
|
||||
pub name: String,
|
||||
pub summary: Option<String>,
|
||||
pub image: Option<String>,
|
||||
pub icon: Option<String>,
|
||||
|
||||
pub preferred_username: Option<String>,
|
||||
pub inbox: Option<String>,
|
||||
pub shared_inbox: Option<String>,
|
||||
pub outbox: Option<String>,
|
||||
pub following: Option<String>,
|
||||
pub followers: Option<String>,
|
||||
|
||||
pub created: ChronoDateTimeUtc,
|
||||
pub updated: ChronoDateTimeUtc,
|
||||
|
||||
// TODO these are also suggested
|
||||
// pub liked: Option<String>,
|
||||
// pub streams: Option<String>,
|
||||
}
|
||||
|
||||
use crate::activitystream::object::{actor::Actor, collection::Collection, document::Image};
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||
pub enum Relation {}
|
||||
pub enum Relation {
|
||||
#[sea_orm(has_many = "super::activity::Entity")]
|
||||
Activity,
|
||||
|
||||
#[sea_orm(has_many = "super::object::Entity")]
|
||||
Object,
|
||||
}
|
||||
|
||||
impl Related<super::activity::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::Activity.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl Related<super::object::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::Object.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
|
||||
impl Base for Model {
|
||||
impl crate::activitystream::Base for Model {
|
||||
fn id(&self) -> Option<&str> {
|
||||
Some(&self.id)
|
||||
}
|
||||
|
@ -29,32 +67,94 @@ impl Base for Model {
|
|||
}
|
||||
|
||||
fn underlying_json_object(self) -> serde_json::Value {
|
||||
let mut map = serde_json::Map::new();
|
||||
map.insert_str("id", Some(&self.id));
|
||||
map.insert_str("type", Some(self.actor_type.as_ref()));
|
||||
map.insert_str("name", Some(&self.name));
|
||||
serde_json::Value::Object(map)
|
||||
crate::activitystream::object()
|
||||
.set_id(Some(&self.id))
|
||||
.set_actor_type(Some(self.actor_type))
|
||||
.set_name(Some(&self.name))
|
||||
.set_summary(self.summary.as_deref())
|
||||
.set_icon(self.icon())
|
||||
.set_image(self.image())
|
||||
.set_preferred_username(self.preferred_username.as_deref())
|
||||
.set_inbox(self.inbox())
|
||||
.set_outbox(self.outbox())
|
||||
.set_following(self.following())
|
||||
.set_followers(self.followers())
|
||||
.underlying_json_object()
|
||||
}
|
||||
}
|
||||
|
||||
impl Object for Model {
|
||||
fn name (&self) -> Option<&str> {
|
||||
impl crate::activitystream::object::Object for Model {
|
||||
fn name(&self) -> Option<&str> {
|
||||
Some(&self.name)
|
||||
}
|
||||
|
||||
fn summary(&self) -> Option<&str> {
|
||||
self.summary.as_deref()
|
||||
}
|
||||
|
||||
fn icon(&self) -> Node<impl Image> {
|
||||
match &self.icon {
|
||||
Some(x) => Node::link(x.to_string()),
|
||||
None => Node::Empty,
|
||||
}
|
||||
}
|
||||
|
||||
fn image(&self) -> Node<impl Image> {
|
||||
match &self.image {
|
||||
Some(x) => Node::link(x.to_string()),
|
||||
None => Node::Empty,
|
||||
}
|
||||
}
|
||||
|
||||
fn published(&self) -> Option<chrono::DateTime<chrono::Utc>> {
|
||||
Some(self.created)
|
||||
}
|
||||
}
|
||||
|
||||
impl Actor for Model {
|
||||
impl crate::activitystream::object::actor::Actor for Model {
|
||||
fn actor_type(&self) -> Option<ActorType> {
|
||||
Some(self.actor_type)
|
||||
}
|
||||
|
||||
fn preferred_username(&self) -> Option<&str> {
|
||||
self.preferred_username.as_deref()
|
||||
}
|
||||
|
||||
fn inbox(&self) -> Node<impl Collection> {
|
||||
Node::link(self.inbox.clone().unwrap_or(format!("https://{}/users/{}/inbox", self.domain, self.name)))
|
||||
}
|
||||
|
||||
fn outbox(&self) -> Node<impl Collection> {
|
||||
Node::link(self.outbox.clone().unwrap_or(format!("https://{}/users/{}/outbox", self.domain, self.name)))
|
||||
}
|
||||
|
||||
fn following(&self) -> Node<impl Collection> {
|
||||
Node::link(self.following.clone().unwrap_or(format!("https://{}/users/{}/following", self.domain, self.name)))
|
||||
}
|
||||
|
||||
fn followers(&self) -> Node<impl Collection> {
|
||||
Node::link(self.following.clone().unwrap_or(format!("https://{}/users/{}/followers", self.domain, self.name)))
|
||||
}
|
||||
}
|
||||
|
||||
impl Model {
|
||||
pub fn new(object: &impl Actor) -> Result<Self, super::FieldError> {
|
||||
let ap_id = object.id().ok_or(super::FieldError("id"))?.to_string();
|
||||
let (domain, name) = activitypub::split_id(&ap_id);
|
||||
Ok(Model {
|
||||
id: object.id().ok_or(super::FieldError("id"))?.to_string(),
|
||||
id: ap_id, name, domain,
|
||||
actor_type: object.actor_type().ok_or(super::FieldError("type"))?,
|
||||
name: object.name().ok_or(super::FieldError("name"))?.to_string(),
|
||||
preferred_username: object.preferred_username().map(|x| x.to_string()),
|
||||
summary: object.summary().map(|x| x.to_string()),
|
||||
icon: object.icon().id().map(|x| x.to_string()),
|
||||
image: object.image().id().map(|x| x.to_string()),
|
||||
inbox: object.inbox().id().map(|x| x.to_string()),
|
||||
outbox: object.inbox().id().map(|x| x.to_string()),
|
||||
shared_inbox: None, // TODO!!! parse endpoints
|
||||
followers: object.followers().id().map(|x| x.to_string()),
|
||||
following: object.following().id().map(|x| x.to_string()),
|
||||
created: object.published().unwrap_or(chrono::Utc::now()),
|
||||
updated: chrono::Utc::now(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue