2024-05-25 05:31:10 +02:00
|
|
|
use sea_orm::{entity::prelude::*, QuerySelect, SelectColumns};
|
2024-03-16 03:27:36 +01:00
|
|
|
|
2024-11-20 19:55:29 +01:00
|
|
|
use apb::{ActorMut, ActorType, BaseMut, DocumentMut, EndpointsMut, ObjectMut, PublicKeyMut};
|
2024-07-15 13:57:03 +02:00
|
|
|
|
2024-07-15 20:20:43 +02:00
|
|
|
use crate::ext::{JsonVec, TypeName};
|
|
|
|
|
|
|
|
#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
|
2024-07-15 13:57:03 +02:00
|
|
|
pub struct Field {
|
2024-07-15 21:48:26 +02:00
|
|
|
#[serde(default)]
|
2024-07-15 13:57:03 +02:00
|
|
|
pub name: String,
|
2024-07-15 21:48:26 +02:00
|
|
|
#[serde(default)]
|
2024-07-15 21:15:29 +02:00
|
|
|
pub value: String,
|
2024-07-15 21:48:26 +02:00
|
|
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
2024-07-15 13:57:03 +02:00
|
|
|
pub verified_at: Option<ChronoDateTimeUtc>,
|
2024-07-15 21:48:26 +02:00
|
|
|
#[serde(default, rename = "type")]
|
2024-07-15 13:57:03 +02:00
|
|
|
pub field_type: String,
|
|
|
|
}
|
|
|
|
|
2024-07-15 20:20:43 +02:00
|
|
|
impl TypeName for Field {
|
|
|
|
fn type_name() -> String {
|
|
|
|
"Field".to_string()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-07-15 21:54:40 +02:00
|
|
|
impl<T: apb::Object> From<T> for Field {
|
|
|
|
fn from(value: T) -> Self {
|
2024-07-15 13:57:03 +02:00
|
|
|
Field {
|
2024-11-20 19:55:29 +01:00
|
|
|
name: value.name().unwrap_or_default().to_string(),
|
|
|
|
value: mdhtml::safe_html(&value.value().unwrap_or_default()),
|
2024-07-15 13:57:03 +02:00
|
|
|
field_type: "PropertyValue".to_string(), // TODO can we try parsing this instead??
|
|
|
|
verified_at: None, // TODO where does verified_at come from? extend apb maybe
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-03-16 05:45:58 +01:00
|
|
|
|
2024-03-16 03:27:36 +01:00
|
|
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
2024-05-24 05:05:14 +02:00
|
|
|
#[sea_orm(table_name = "actors")]
|
2024-03-16 03:27:36 +01:00
|
|
|
pub struct Model {
|
|
|
|
#[sea_orm(primary_key)]
|
2024-05-25 04:37:17 +02:00
|
|
|
pub internal: i64,
|
2024-05-24 05:05:14 +02:00
|
|
|
#[sea_orm(unique)]
|
2024-05-25 04:37:17 +02:00
|
|
|
pub id: String,
|
2024-03-16 05:45:58 +01:00
|
|
|
pub actor_type: ActorType,
|
2024-05-25 04:37:17 +02:00
|
|
|
pub domain: String,
|
2024-03-21 02:50:48 +01:00
|
|
|
pub name: Option<String>,
|
2024-03-21 01:09:33 +01:00
|
|
|
pub summary: Option<String>,
|
|
|
|
pub image: Option<String>,
|
|
|
|
pub icon: Option<String>,
|
2024-05-24 05:05:14 +02:00
|
|
|
pub preferred_username: String,
|
2024-07-15 20:20:43 +02:00
|
|
|
pub fields: JsonVec<Field>,
|
2024-03-21 01:09:33 +01:00
|
|
|
pub inbox: Option<String>,
|
|
|
|
pub shared_inbox: Option<String>,
|
|
|
|
pub outbox: Option<String>,
|
|
|
|
pub following: Option<String>,
|
|
|
|
pub followers: Option<String>,
|
2024-05-24 05:05:14 +02:00
|
|
|
pub following_count: i32,
|
|
|
|
pub followers_count: i32,
|
|
|
|
pub statuses_count: i32,
|
2024-03-21 02:11:31 +01:00
|
|
|
pub public_key: String,
|
|
|
|
pub private_key: Option<String>,
|
2024-05-25 07:00:03 +02:00
|
|
|
pub published: ChronoDateTimeUtc,
|
2024-03-21 01:09:33 +01:00
|
|
|
pub updated: ChronoDateTimeUtc,
|
2024-07-15 20:20:43 +02:00
|
|
|
pub also_known_as: JsonVec<String>,
|
2024-07-15 13:57:03 +02:00
|
|
|
pub moved_to: Option<String>,
|
2024-03-16 03:27:36 +01:00
|
|
|
}
|
|
|
|
|
2024-05-24 05:05:14 +02:00
|
|
|
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
|
|
|
pub enum Relation {
|
|
|
|
#[sea_orm(has_many = "super::activity::Entity")]
|
|
|
|
Activities,
|
|
|
|
#[sea_orm(has_many = "super::addressing::Entity")]
|
|
|
|
Addressing,
|
|
|
|
#[sea_orm(has_many = "super::announce::Entity")]
|
|
|
|
Announces,
|
|
|
|
#[sea_orm(has_many = "super::config::Entity")]
|
|
|
|
Configs,
|
|
|
|
#[sea_orm(has_many = "super::credential::Entity")]
|
|
|
|
Credentials,
|
|
|
|
#[sea_orm(
|
|
|
|
belongs_to = "super::instance::Entity",
|
2024-05-25 04:37:17 +02:00
|
|
|
from = "Column::Domain",
|
|
|
|
to = "super::instance::Column::Domain",
|
2024-05-24 05:05:14 +02:00
|
|
|
on_update = "Cascade",
|
|
|
|
on_delete = "NoAction"
|
|
|
|
)]
|
|
|
|
Instances,
|
2024-06-23 17:27:49 +02:00
|
|
|
#[sea_orm(has_many = "super::dislike::Entity")]
|
|
|
|
Dislikes,
|
2024-05-24 05:05:14 +02:00
|
|
|
#[sea_orm(has_many = "super::like::Entity")]
|
|
|
|
Likes,
|
|
|
|
#[sea_orm(has_many = "super::mention::Entity")]
|
|
|
|
Mentions,
|
2024-06-26 03:54:15 +02:00
|
|
|
#[sea_orm(has_many = "super::notification::Entity")]
|
|
|
|
Notifications,
|
2024-05-24 05:05:14 +02:00
|
|
|
#[sea_orm(has_many = "super::object::Entity")]
|
|
|
|
Objects,
|
2024-05-26 18:41:56 +02:00
|
|
|
#[sea_orm(has_many = "super::relation::Entity")]
|
|
|
|
Relations,
|
2024-05-24 05:05:14 +02:00
|
|
|
#[sea_orm(has_many = "super::session::Entity")]
|
|
|
|
Sessions,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Related<super::activity::Entity> for Entity {
|
|
|
|
fn to() -> RelationDef {
|
|
|
|
Relation::Activities.def()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Related<super::addressing::Entity> for Entity {
|
|
|
|
fn to() -> RelationDef {
|
|
|
|
Relation::Addressing.def()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Related<super::announce::Entity> for Entity {
|
|
|
|
fn to() -> RelationDef {
|
|
|
|
Relation::Announces.def()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Related<super::config::Entity> for Entity {
|
|
|
|
fn to() -> RelationDef {
|
|
|
|
Relation::Configs.def()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Related<super::credential::Entity> for Entity {
|
|
|
|
fn to() -> RelationDef {
|
|
|
|
Relation::Credentials.def()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Related<super::instance::Entity> for Entity {
|
|
|
|
fn to() -> RelationDef {
|
|
|
|
Relation::Instances.def()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-06-23 17:27:49 +02:00
|
|
|
impl Related<super::dislike::Entity> for Entity {
|
|
|
|
fn to() -> RelationDef {
|
|
|
|
Relation::Dislikes.def()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-24 05:05:14 +02:00
|
|
|
impl Related<super::like::Entity> for Entity {
|
|
|
|
fn to() -> RelationDef {
|
|
|
|
Relation::Likes.def()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Related<super::mention::Entity> for Entity {
|
|
|
|
fn to() -> RelationDef {
|
|
|
|
Relation::Mentions.def()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-06-26 03:54:15 +02:00
|
|
|
impl Related<super::notification::Entity> for Entity {
|
|
|
|
fn to() -> RelationDef {
|
|
|
|
Relation::Notifications.def()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-24 05:05:14 +02:00
|
|
|
impl Related<super::object::Entity> for Entity {
|
|
|
|
fn to() -> RelationDef {
|
|
|
|
Relation::Objects.def()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-26 18:41:56 +02:00
|
|
|
impl Related<super::relation::Entity> for Entity {
|
|
|
|
fn to() -> RelationDef {
|
|
|
|
Relation::Relations.def()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-24 05:05:14 +02:00
|
|
|
impl Related<super::session::Entity> for Entity {
|
|
|
|
fn to() -> RelationDef {
|
|
|
|
Relation::Sessions.def()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ActiveModelBehavior for ActiveModel {}
|
|
|
|
|
2024-05-25 05:31:10 +02:00
|
|
|
impl Entity {
|
|
|
|
pub fn find_by_ap_id(id: &str) -> Select<Entity> {
|
|
|
|
Entity::find().filter(Column::Id.eq(id))
|
|
|
|
}
|
|
|
|
|
2024-05-25 07:22:41 +02:00
|
|
|
pub fn delete_by_ap_id(id: &str) -> sea_orm::DeleteMany<Entity> {
|
|
|
|
Entity::delete_many().filter(Column::Id.eq(id))
|
|
|
|
}
|
|
|
|
|
2024-06-06 04:15:27 +02:00
|
|
|
pub async fn ap_to_internal(id: &str, db: &impl ConnectionTrait) -> Result<Option<i64>, DbErr> {
|
2024-05-25 05:31:10 +02:00
|
|
|
Entity::find()
|
|
|
|
.filter(Column::Id.eq(id))
|
|
|
|
.select_only()
|
|
|
|
.select_column(Column::Internal)
|
|
|
|
.into_tuple::<i64>()
|
|
|
|
.one(db)
|
2024-06-01 05:21:57 +02:00
|
|
|
.await
|
2024-05-25 05:31:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-12-26 15:38:37 +01:00
|
|
|
impl crate::ext::IntoActivityPub for Model {
|
2024-12-26 20:40:49 +01:00
|
|
|
fn into_activity_pub_json(self, ctx: &crate::Context) -> serde_json::Value {
|
|
|
|
let is_local = ctx.is_local(&self.id);
|
|
|
|
let id = ctx.id(&self.id);
|
2024-05-31 04:07:39 +02:00
|
|
|
apb::new()
|
2024-11-20 19:55:29 +01:00
|
|
|
.set_id(Some(self.id.clone()))
|
2024-04-19 03:28:39 +02:00
|
|
|
.set_actor_type(Some(self.actor_type))
|
2024-11-20 19:55:29 +01:00
|
|
|
.set_name(self.name)
|
|
|
|
.set_summary(self.summary)
|
2024-04-19 03:28:39 +02:00
|
|
|
.set_icon(apb::Node::maybe_object(self.icon.map(|i|
|
2024-05-31 04:07:39 +02:00
|
|
|
apb::new()
|
2024-04-19 03:28:39 +02:00
|
|
|
.set_document_type(Some(apb::DocumentType::Image))
|
|
|
|
.set_url(apb::Node::link(i.clone()))
|
|
|
|
)))
|
|
|
|
.set_image(apb::Node::maybe_object(self.image.map(|i|
|
2024-05-31 04:07:39 +02:00
|
|
|
apb::new()
|
2024-04-19 03:28:39 +02:00
|
|
|
.set_document_type(Some(apb::DocumentType::Image))
|
|
|
|
.set_url(apb::Node::link(i.clone()))
|
|
|
|
)))
|
2024-07-15 13:57:03 +02:00
|
|
|
.set_attachment(apb::Node::array(
|
2024-07-15 20:20:43 +02:00
|
|
|
self.fields.0
|
2024-07-15 13:57:03 +02:00
|
|
|
.into_iter()
|
2024-07-15 14:03:22 +02:00
|
|
|
.filter_map(|x| serde_json::to_value(x).ok())
|
2024-07-15 13:57:03 +02:00
|
|
|
.collect()
|
|
|
|
))
|
2024-05-25 07:00:03 +02:00
|
|
|
.set_published(Some(self.published))
|
2024-06-22 06:13:15 +02:00
|
|
|
.set_updated(if self.updated != self.published { Some(self.updated) } else { None })
|
2024-11-20 19:55:29 +01:00
|
|
|
.set_preferred_username(Some(self.preferred_username))
|
2024-05-02 00:47:11 +02:00
|
|
|
.set_statuses_count(Some(self.statuses_count as u64))
|
2024-12-26 20:40:49 +01:00
|
|
|
// local users may want to hide these! default to hidden, and downstream we can opt-in to
|
|
|
|
// showing them. for remote users we assume the number is already "protected" by remote
|
|
|
|
// instance so we just show it
|
|
|
|
.set_followers_count(if is_local { None } else { Some(self.followers_count as u64) })
|
|
|
|
.set_following_count(if is_local { None } else { Some(self.following_count as u64) })
|
|
|
|
.set_inbox(if is_local { apb::Node::link(crate::url!(ctx, "/actors/{id}/inbox")) } else { apb::Node::maybe_link(self.inbox) })
|
|
|
|
.set_outbox(if is_local { apb::Node::link(crate::url!(ctx, "/actors/{id}/outbox")) } else { apb::Node::maybe_link(self.outbox) })
|
|
|
|
.set_following(if is_local { apb::Node::link(crate::url!(ctx, "/actors{id}/following")) } else { apb::Node::maybe_link(self.following) })
|
|
|
|
.set_followers(if is_local { apb::Node::link(crate::url!(ctx, "/actors/{id}/followers")) } else { apb::Node::maybe_link(self.followers) })
|
2024-04-30 01:51:38 +02:00
|
|
|
.set_public_key(apb::Node::object(
|
2024-05-31 04:07:39 +02:00
|
|
|
apb::new()
|
2024-11-20 19:55:29 +01:00
|
|
|
.set_id(Some(format!("{}#main-key", self.id)))
|
|
|
|
.set_owner(Some(self.id))
|
|
|
|
.set_public_key_pem(self.public_key)
|
2024-04-30 01:51:38 +02:00
|
|
|
))
|
2024-05-15 18:51:34 +02:00
|
|
|
.set_endpoints(apb::Node::object(
|
2024-05-31 04:07:39 +02:00
|
|
|
apb::new()
|
2024-12-26 20:40:49 +01:00
|
|
|
.set_shared_inbox(if is_local { Some(crate::url!(ctx, "/inbox")) } else { self.shared_inbox })
|
|
|
|
.set_proxy_url(if is_local { Some(crate::url!(ctx, "/fetch")) } else { None })
|
2024-05-15 18:51:34 +02:00
|
|
|
))
|
2024-07-15 20:20:43 +02:00
|
|
|
.set_also_known_as(apb::Node::links(self.also_known_as.0))
|
2024-07-15 13:57:03 +02:00
|
|
|
.set_moved_to(apb::Node::maybe_link(self.moved_to))
|
2024-04-30 01:51:38 +02:00
|
|
|
.set_discoverable(Some(true))
|
2024-04-19 03:28:39 +02:00
|
|
|
}
|
2024-03-23 06:32:15 +01:00
|
|
|
}
|