forked from alemi/upub
feat: process and store remote attachment urls
This commit is contained in:
parent
cd9d3f9db4
commit
c595f5f5e3
7 changed files with 154 additions and 2 deletions
66
src/migrations/m20240421_000001_add_attachments.rs
Normal file
66
src/migrations/m20240421_000001_add_attachments.rs
Normal 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,
|
||||||
|
}
|
|
@ -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
61
src/model/attachment.rs
Normal 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 {}
|
|
@ -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")]
|
||||||
|
|
|
@ -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 {}
|
||||||
|
|
|
@ -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?;
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in a new issue