edits federating, need tests and api adjustments

This commit is contained in:
Felix Ableitner 2023-11-20 17:04:52 +01:00
parent c48f26c908
commit afbb81c0d1
9 changed files with 60 additions and 21 deletions

View File

@ -6,7 +6,6 @@ use crate::federation::activities::create_or_update_article::{
}; };
use crate::federation::objects::article::DbArticle; use crate::federation::objects::article::DbArticle;
use crate::federation::objects::instance::DbInstance; use crate::federation::objects::instance::DbInstance;
use crate::utils::generate_object_id;
use activitypub_federation::config::Data; use activitypub_federation::config::Data;
use activitypub_federation::fetch::object_id::ObjectId; use activitypub_federation::fetch::object_id::ObjectId;
use anyhow::anyhow; use anyhow::anyhow;
@ -41,7 +40,13 @@ async fn create_article(
Form(create_article): Form<CreateArticle>, Form(create_article): Form<CreateArticle>,
) -> MyResult<Json<DbArticle>> { ) -> MyResult<Json<DbArticle>> {
let local_instance_id = data.local_instance().ap_id; let local_instance_id = data.local_instance().ap_id;
let ap_id = generate_object_id(local_instance_id.inner())?.into(); let ap_id = Url::parse(&format!(
"http://{}:{}/article/{}",
local_instance_id.inner().domain().unwrap(),
local_instance_id.inner().port().unwrap(),
create_article.title
))?
.into();
let article = DbArticle { let article = DbArticle {
title: create_article.title, title: create_article.title,
text: create_article.text, text: create_article.text,

View File

@ -15,7 +15,7 @@ pub mod routes;
pub async fn federation_config(hostname: &str) -> Result<FederationConfig<DatabaseHandle>, Error> { pub async fn federation_config(hostname: &str) -> Result<FederationConfig<DatabaseHandle>, Error> {
let ap_id = Url::parse(&format!("http://{}", hostname))?.into(); let ap_id = Url::parse(&format!("http://{}", hostname))?.into();
let articles_id = Url::parse(&format!("http://{}/articles", hostname))?.into(); let articles_id = Url::parse(&format!("http://{}/all_articles", hostname))?.into();
let inbox = Url::parse(&format!("http://{}/inbox", hostname))?; let inbox = Url::parse(&format!("http://{}/inbox", hostname))?;
let keypair = generate_actor_keypair()?; let keypair = generate_actor_keypair()?;
let local_instance = DbInstance { let local_instance = DbInstance {

View File

@ -1,6 +1,6 @@
use crate::error::MyResult; use crate::error::MyResult;
use crate::federation::objects::edit::DbEdit; use crate::federation::objects::edit::DbEdit;
use crate::federation::objects::edits_collection::{ApubEditCollection, DbEditCollection}; use crate::federation::objects::edits_collection::DbEditCollection;
use crate::federation::objects::instance::DbInstance; use crate::federation::objects::instance::DbInstance;
use crate::{database::DatabaseHandle, error::Error}; use crate::{database::DatabaseHandle, error::Error};
use activitypub_federation::fetch::collection_id::CollectionId; use activitypub_federation::fetch::collection_id::CollectionId;

View File

@ -2,7 +2,7 @@ use crate::database::DatabaseHandle;
use crate::error::Error; use crate::error::Error;
use crate::federation::objects::article::{ApubArticle, DbArticle}; use crate::federation::objects::article::{ApubArticle, DbArticle};
use crate::federation::objects::instance::DbInstance; use crate::federation::objects::instance::DbInstance;
use crate::utils::generate_object_id;
use activitypub_federation::kinds::collection::CollectionType; use activitypub_federation::kinds::collection::CollectionType;
use activitypub_federation::{ use activitypub_federation::{
config::Data, config::Data,

View File

@ -37,25 +37,28 @@ impl Object for DbEdit {
type Error = Error; type Error = Error;
async fn read_from_id( async fn read_from_id(
object_id: Url, _object_id: Url,
data: &Data<Self::DataType>, _data: &Data<Self::DataType>,
) -> Result<Option<Self>, Self::Error> { ) -> Result<Option<Self>, Self::Error> {
todo!() todo!()
} }
async fn into_json(self, data: &Data<Self::DataType>) -> Result<Self::Kind, Self::Error> { async fn into_json(self, _data: &Data<Self::DataType>) -> Result<Self::Kind, Self::Error> {
todo!() todo!()
} }
async fn verify( async fn verify(
json: &Self::Kind, _json: &Self::Kind,
expected_domain: &Url, _expected_domain: &Url,
data: &Data<Self::DataType>, _data: &Data<Self::DataType>,
) -> Result<(), Self::Error> { ) -> Result<(), Self::Error> {
todo!() todo!()
} }
async fn from_json(json: Self::Kind, data: &Data<Self::DataType>) -> Result<Self, Self::Error> { async fn from_json(
_json: Self::Kind,
_data: &Data<Self::DataType>,
) -> Result<Self, Self::Error> {
todo!() todo!()
} }
} }

View File

@ -1,10 +1,9 @@
use crate::database::DatabaseHandle; use crate::database::DatabaseHandle;
use crate::error::Error; use crate::error::Error;
use crate::federation::objects::article::{ApubArticle, DbArticle}; use crate::federation::objects::article::DbArticle;
use crate::federation::objects::edit::{ApubEdit, DbEdit}; use crate::federation::objects::edit::{ApubEdit, DbEdit};
use crate::federation::objects::instance::DbInstance;
use crate::utils::generate_object_id; use activitypub_federation::kinds::collection::OrderedCollectionType;
use activitypub_federation::kinds::collection::{CollectionType, OrderedCollectionType};
use activitypub_federation::{ use activitypub_federation::{
config::Data, config::Data,
traits::{Collection, Object}, traits::{Collection, Object},
@ -75,7 +74,7 @@ impl Collection for DbEditCollection {
let edits = let edits =
try_join_all(apub.items.into_iter().map(|i| DbEdit::from_json(i, data))).await?; try_join_all(apub.items.into_iter().map(|i| DbEdit::from_json(i, data))).await?;
let mut articles = data.articles.lock().unwrap(); let mut articles = data.articles.lock().unwrap();
let mut article = articles.get_mut(owner.ap_id.inner()).unwrap(); let article = articles.get_mut(owner.ap_id.inner()).unwrap();
for e in edits.clone() { for e in edits.clone() {
// TODO: edits need a unique id to avoid pushing duplicates // TODO: edits need a unique id to avoid pushing duplicates
article.edits.push(e); article.edits.push(e);

View File

@ -1,4 +1,4 @@
use crate::error::{Error, MyResult}; use crate::error::Error;
use crate::federation::objects::articles_collection::DbArticleCollection; use crate::federation::objects::articles_collection::DbArticleCollection;
use crate::{database::DatabaseHandle, federation::activities::follow::Follow}; use crate::{database::DatabaseHandle, federation::activities::follow::Follow};
use activitypub_federation::activity_sending::SendActivityTask; use activitypub_federation::activity_sending::SendActivityTask;

View File

@ -10,9 +10,12 @@ use activitypub_federation::config::Data;
use activitypub_federation::protocol::context::WithContext; use activitypub_federation::protocol::context::WithContext;
use activitypub_federation::traits::Object; use activitypub_federation::traits::Object;
use activitypub_federation::traits::{ActivityHandler, Collection}; use activitypub_federation::traits::{ActivityHandler, Collection};
use axum::extract::Path;
use crate::federation::activities::create_or_update_article::CreateOrUpdateArticle; use crate::federation::activities::create_or_update_article::CreateOrUpdateArticle;
use crate::federation::objects::article::ApubArticle;
use crate::federation::objects::articles_collection::{ArticleCollection, DbArticleCollection}; use crate::federation::objects::articles_collection::{ArticleCollection, DbArticleCollection};
use crate::federation::objects::edits_collection::{ApubEditCollection, DbEditCollection};
use axum::response::IntoResponse; use axum::response::IntoResponse;
use axum::routing::{get, post}; use axum::routing::{get, post};
use axum::Router; use axum::Router;
@ -23,7 +26,9 @@ use url::Url;
pub fn federation_routes() -> Router { pub fn federation_routes() -> Router {
Router::new() Router::new()
.route("/", get(http_get_instance)) .route("/", get(http_get_instance))
.route("/articles", get(http_get_articles)) .route("/all_articles", get(http_get_all_articles))
.route("/article/:title", get(http_get_article))
.route("/article/:title/edits", get(http_get_article_edits))
.route("/inbox", post(http_post_inbox)) .route("/inbox", post(http_post_inbox))
} }
@ -37,13 +42,39 @@ async fn http_get_instance(
} }
#[debug_handler] #[debug_handler]
async fn http_get_articles( async fn http_get_all_articles(
data: Data<DatabaseHandle>, data: Data<DatabaseHandle>,
) -> MyResult<FederationJson<WithContext<ArticleCollection>>> { ) -> MyResult<FederationJson<WithContext<ArticleCollection>>> {
let collection = DbArticleCollection::read_local(&data.local_instance(), &data).await?; let collection = DbArticleCollection::read_local(&data.local_instance(), &data).await?;
Ok(FederationJson(WithContext::new_default(collection))) Ok(FederationJson(WithContext::new_default(collection)))
} }
#[debug_handler]
async fn http_get_article(
Path(title): Path<String>,
data: Data<DatabaseHandle>,
) -> MyResult<FederationJson<WithContext<ApubArticle>>> {
let article = {
let lock = data.articles.lock().unwrap();
lock.values().find(|a| a.title == title).unwrap().clone()
};
let json = article.into_json(&data).await?;
Ok(FederationJson(WithContext::new_default(json)))
}
#[debug_handler]
async fn http_get_article_edits(
Path(title): Path<String>,
data: Data<DatabaseHandle>,
) -> MyResult<FederationJson<WithContext<ApubEditCollection>>> {
let article = {
let lock = data.articles.lock().unwrap();
lock.values().find(|a| a.title == title).unwrap().clone()
};
let json = DbEditCollection::read_local(&article, &data).await?;
Ok(FederationJson(WithContext::new_default(json)))
}
/// List of all activities which this actor can receive. /// List of all activities which this actor can receive.
#[derive(Deserialize, Serialize, Debug)] #[derive(Deserialize, Serialize, Debug)]
#[serde(untagged)] #[serde(untagged)]

View File

@ -4,11 +4,12 @@ use url::{ParseError, Url};
/// Just generate random url as object id. In a real project, you probably want to use /// Just generate random url as object id. In a real project, you probably want to use
/// an url which contains the database id for easy retrieval (or store the random id in db). /// an url which contains the database id for easy retrieval (or store the random id in db).
pub fn generate_object_id(domain: &Url) -> Result<Url, ParseError> { pub fn generate_object_id(domain: &Url) -> Result<Url, ParseError> {
let port = domain.port().unwrap();
let domain = domain.domain().unwrap(); let domain = domain.domain().unwrap();
let id: String = thread_rng() let id: String = thread_rng()
.sample_iter(&Alphanumeric) .sample_iter(&Alphanumeric)
.take(7) .take(7)
.map(char::from) .map(char::from)
.collect(); .collect();
Url::parse(&format!("http://{}/objects/{}", domain, id)) Url::parse(&format!("http://{}:{}/objects/{}", domain,port, id))
} }