feat: process and store remote attachment urls

This commit is contained in:
əlemi 2024-04-21 22:58:33 +02:00
parent cd9d3f9db4
commit c595f5f5e3
Signed by: alemi
GPG key ID: A4895B84D311642C
7 changed files with 154 additions and 2 deletions

View file

@ -0,0 +1,66 @@
use sea_orm_migration::prelude::*;
#[derive(DeriveMigrationName)]
pub struct Migration;
#[async_trait::async_trait]
impl MigrationTrait for Migration {
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.create_table(
Table::create()
.table(Attachments::Table)
.col(
ColumnDef::new(Attachments::Id)
.integer()
.not_null()
.auto_increment()
.primary_key()
)
.col(ColumnDef::new(Attachments::Url).string().not_null())
.col(ColumnDef::new(Attachments::Object).string().not_null())
.col(ColumnDef::new(Attachments::DocumentType).string().not_null())
.col(ColumnDef::new(Attachments::Name).string().null())
.col(ColumnDef::new(Attachments::MediaType).string().not_null())
.col(ColumnDef::new(Attachments::Created).date_time().not_null())
.to_owned()
)
.await?;
manager
.create_index(
Index::create()
.name("attachment-object-index")
.table(Attachments::Table)
.col(Attachments::Object)
.to_owned()
)
.await?;
Ok(())
}
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.drop_table(Table::drop().table(Attachments::Table).to_owned())
.await?;
manager
.drop_index(Index::drop().name("attachment-object-index").to_owned())
.await?;
Ok(())
}
}
#[derive(DeriveIden)]
enum Attachments {
Table,
Id,
Url,
Object,
DocumentType,
Name,
MediaType,
Created,
}

View file

@ -10,6 +10,7 @@ mod m20240324_000001_add_addressing;
mod m20240325_000001_add_deliveries; mod m20240325_000001_add_deliveries;
mod m20240325_000002_add_system_key; mod m20240325_000002_add_system_key;
mod m20240418_000001_add_statuses_and_reply_to; mod m20240418_000001_add_statuses_and_reply_to;
mod m20240421_000001_add_attachments;
pub struct Migrator; pub struct Migrator;
@ -27,6 +28,7 @@ impl MigratorTrait for Migrator {
Box::new(m20240325_000001_add_deliveries::Migration), Box::new(m20240325_000001_add_deliveries::Migration),
Box::new(m20240325_000002_add_system_key::Migration), Box::new(m20240325_000002_add_system_key::Migration),
Box::new(m20240418_000001_add_statuses_and_reply_to::Migration), Box::new(m20240418_000001_add_statuses_and_reply_to::Migration),
Box::new(m20240421_000001_add_attachments::Migration),
] ]
} }
} }

61
src/model/attachment.rs Normal file
View file

@ -0,0 +1,61 @@
use apb::{DocumentMut, ObjectMut};
use sea_orm::{entity::prelude::*, Set};
use crate::routes::activitypub::jsonld::LD;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[sea_orm(table_name = "attachments")]
pub struct Model {
#[sea_orm(primary_key)]
pub id: i64,
pub url: String,
pub object: String,
pub document_type: apb::DocumentType,
pub name: Option<String>,
pub media_type: String,
pub created: ChronoDateTimeUtc,
}
impl ActiveModel {
pub fn new(document: &impl apb::Document, object: String) -> Result<ActiveModel, super::FieldError> {
Ok(ActiveModel {
id: sea_orm::ActiveValue::NotSet,
object: Set(object),
url: Set(document.url().id().ok_or(super::FieldError("url"))?),
document_type: Set(document.document_type().ok_or(super::FieldError("type"))?),
media_type: Set(document.media_type().ok_or(super::FieldError("mediaType"))?.to_string()),
name: Set(document.name().map(|x| x.to_string())),
created: Set(document.published().unwrap_or(chrono::Utc::now())),
})
}
}
impl Model {
pub fn ap(self) -> serde_json::Value {
serde_json::Value::new_object()
.set_url(apb::Node::link(self.url))
.set_document_type(Some(self.document_type))
.set_media_type(Some(&self.media_type))
.set_name(self.name.as_deref())
.set_published(Some(self.created))
}
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {
#[sea_orm(
belongs_to = "super::object::Entity",
from = "Column::Object",
to = "super::object::Column::Id"
)]
Object,
}
impl Related<super::object::Entity> for Entity {
fn to() -> RelationDef {
Relation::Object.def()
}
}
impl ActiveModelBehavior for ActiveModel {}

View file

@ -10,6 +10,7 @@ pub mod like;
pub mod credential; pub mod credential;
pub mod session; pub mod session;
pub mod delivery; pub mod delivery;
pub mod attachment;
pub mod application; pub mod application;
#[cfg(feature = "faker")] #[cfg(feature = "faker")]

View file

@ -48,7 +48,7 @@ impl Model {
bcc: object.bcc().into(), bcc: object.bcc().into(),
}) })
} }
// TODO this is used outside /routes, maybe move in model?
pub fn ap(self) -> serde_json::Value { pub fn ap(self) -> serde_json::Value {
serde_json::Value::new_object() serde_json::Value::new_object()
.set_id(Some(&self.id)) .set_id(Some(&self.id))
@ -81,6 +81,9 @@ pub enum Relation {
#[sea_orm(has_many = "super::addressing::Entity")] #[sea_orm(has_many = "super::addressing::Entity")]
Addressing, Addressing,
#[sea_orm(has_many = "super::attachment::Entity")]
Attachment,
} }
impl Related<super::activity::Entity> for Entity { impl Related<super::activity::Entity> for Entity {
@ -101,4 +104,10 @@ impl Related<super::addressing::Entity> for Entity {
} }
} }
impl Related<super::attachment::Entity> for Entity {
fn to() -> RelationDef {
Relation::Attachment.def()
}
}
impl ActiveModelBehavior for ActiveModel {} impl ActiveModelBehavior for ActiveModel {}

View file

@ -1,6 +1,6 @@
use std::collections::BTreeMap; use std::collections::BTreeMap;
use apb::target::Addressed; use apb::{target::Addressed, Object};
use base64::Engine; use base64::Engine;
use reqwest::{header::{ACCEPT, CONTENT_TYPE, USER_AGENT}, Method, Response}; use reqwest::{header::{ACCEPT, CONTENT_TYPE, USER_AGENT}, Method, Response};
use sea_orm::{EntityTrait, IntoActiveModel}; use sea_orm::{EntityTrait, IntoActiveModel};
@ -131,6 +131,13 @@ impl Fetcher for Context {
let addressed = object.addressed(); let addressed = object.addressed();
let object_model = model::object::Model::new(&object)?; let object_model = model::object::Model::new(&object)?;
for attachment in object.attachment() {
let attachment_model = model::attachment::ActiveModel::new(&attachment, object_model.id.clone())?;
model::attachment::Entity::insert(attachment_model)
.exec(self.db())
.await?;
}
let expanded_addresses = self.expand_addressing(addressed).await?; let expanded_addresses = self.expand_addressing(addressed).await?;
self.address_to(None, Some(&object_model.id), &expanded_addresses).await?; self.address_to(None, Some(&object_model.id), &expanded_addresses).await?;

View file

@ -33,6 +33,12 @@ impl apb::server::Inbox for Context {
let oid = object_model.id.clone(); let oid = object_model.id.clone();
model::object::Entity::insert(object_model.into_active_model()).exec(self.db()).await?; model::object::Entity::insert(object_model.into_active_model()).exec(self.db()).await?;
model::activity::Entity::insert(activity_model.into_active_model()).exec(self.db()).await?; model::activity::Entity::insert(activity_model.into_active_model()).exec(self.db()).await?;
for attachment in object_node.attachment() {
let attachment_model = model::attachment::ActiveModel::new(&attachment, oid.clone())?;
model::attachment::Entity::insert(attachment_model)
.exec(self.db())
.await?;
}
let expanded_addressing = self.expand_addressing(activity.addressed()).await?; let expanded_addressing = self.expand_addressing(activity.addressed()).await?;
self.address_to(Some(&aid), Some(&oid), &expanded_addressing).await?; self.address_to(Some(&aid), Some(&oid), &expanded_addressing).await?;
tracing::info!("{} posted {}", aid, oid); tracing::info!("{} posted {}", aid, oid);