diff --git a/.sqlx/query-18cd95c5c4ae2007101d36083cc6b6d3d6c60788a94babf1b2d5f2e2e858dcc3.json b/.sqlx/query-18cd95c5c4ae2007101d36083cc6b6d3d6c60788a94babf1b2d5f2e2e858dcc3.json deleted file mode 100644 index 31d182a..0000000 --- a/.sqlx/query-18cd95c5c4ae2007101d36083cc6b6d3d6c60788a94babf1b2d5f2e2e858dcc3.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "INSERT INTO ap_objects \n (\n kind,\n object\n )\n VALUES\n (\n $1, \n $2\n );", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Text", - "Text" - ] - }, - "nullable": [] - }, - "hash": "18cd95c5c4ae2007101d36083cc6b6d3d6c60788a94babf1b2d5f2e2e858dcc3" -} diff --git a/.sqlx/query-596f602fe978bf4391c8208b614a75a8fd85524bdf971441664475714e6c34ce.json b/.sqlx/query-596f602fe978bf4391c8208b614a75a8fd85524bdf971441664475714e6c34ce.json new file mode 100644 index 0000000..aea6721 --- /dev/null +++ b/.sqlx/query-596f602fe978bf4391c8208b614a75a8fd85524bdf971441664475714e6c34ce.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT activity_id\n FROM\n poll_person_checkpoints\n WHERE\n person_id = (SELECT ID FROM persons WHERE html_url = $1);", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "activity_id", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [ + false + ] + }, + "hash": "596f602fe978bf4391c8208b614a75a8fd85524bdf971441664475714e6c34ce" +} diff --git a/.sqlx/query-5d1e3c4666a37357515ae47e15c2f9ee5e0e7abb0d5ac1fbe2e996b2a6d2454e.json b/.sqlx/query-5d1e3c4666a37357515ae47e15c2f9ee5e0e7abb0d5ac1fbe2e996b2a6d2454e.json new file mode 100644 index 0000000..cc5733b --- /dev/null +++ b/.sqlx/query-5d1e3c4666a37357515ae47e15c2f9ee5e0e7abb0d5ac1fbe2e996b2a6d2454e.json @@ -0,0 +1,16 @@ +{ + "db_name": "PostgreSQL", + "query": "INSERT INTO ap_repository_objects \n (\n readable,\n activity,\n repository_id\n )\n VALUES\n (\n $1, \n (SELECT ID FROM ap_objects WHERE UUID = $2),\n (SELECT ID FROM repositories WHERE html_url = $3)\n );", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "TextArray", + "Uuid", + "Text" + ] + }, + "nullable": [] + }, + "hash": "5d1e3c4666a37357515ae47e15c2f9ee5e0e7abb0d5ac1fbe2e996b2a6d2454e" +} diff --git a/.sqlx/query-a2b66cdb40f1e0839ecd7568173483ff43e154be987efd7f22541cb506222772.json b/.sqlx/query-a2b66cdb40f1e0839ecd7568173483ff43e154be987efd7f22541cb506222772.json new file mode 100644 index 0000000..b888173 --- /dev/null +++ b/.sqlx/query-a2b66cdb40f1e0839ecd7568173483ff43e154be987efd7f22541cb506222772.json @@ -0,0 +1,16 @@ +{ + "db_name": "PostgreSQL", + "query": "INSERT INTO ap_person_objects \n (\n readable,\n activity,\n person_id\n )\n VALUES\n (\n $1, \n (SELECT ID FROM ap_objects WHERE UUID = $2),\n (SELECT ID FROM persons WHERE html_url = $3)\n );", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "TextArray", + "Uuid", + "Text" + ] + }, + "nullable": [] + }, + "hash": "a2b66cdb40f1e0839ecd7568173483ff43e154be987efd7f22541cb506222772" +} diff --git a/.sqlx/query-a32f1c013b0f3142059e76cbf7424b5964c39894bf1dca5346f340b159af701d.json b/.sqlx/query-a32f1c013b0f3142059e76cbf7424b5964c39894bf1dca5346f340b159af701d.json new file mode 100644 index 0000000..2e01dd7 --- /dev/null +++ b/.sqlx/query-a32f1c013b0f3142059e76cbf7424b5964c39894bf1dca5346f340b159af701d.json @@ -0,0 +1,70 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT \n object_id,\n context,\n attributed_to,\n created,\n committed,\n committed_by,\n hash,\n summary,\n description\n FROM\n commits\n WHERE\n object_id = $1;", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "object_id", + "type_info": "Text" + }, + { + "ordinal": 1, + "name": "context", + "type_info": "Text" + }, + { + "ordinal": 2, + "name": "attributed_to", + "type_info": "Text" + }, + { + "ordinal": 3, + "name": "created", + "type_info": "Timestamptz" + }, + { + "ordinal": 4, + "name": "committed", + "type_info": "Timestamptz" + }, + { + "ordinal": 5, + "name": "committed_by", + "type_info": "Text" + }, + { + "ordinal": 6, + "name": "hash", + "type_info": "Text" + }, + { + "ordinal": 7, + "name": "summary", + "type_info": "Text" + }, + { + "ordinal": 8, + "name": "description", + "type_info": "Text" + } + ], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [ + false, + false, + false, + false, + false, + false, + false, + false, + true + ] + }, + "hash": "a32f1c013b0f3142059e76cbf7424b5964c39894bf1dca5346f340b159af701d" +} diff --git a/.sqlx/query-b81fe0328a6ba2c00723cd09d87ee8d7867ef30d2f3506367d9ed07d23555650.json b/.sqlx/query-b81fe0328a6ba2c00723cd09d87ee8d7867ef30d2f3506367d9ed07d23555650.json new file mode 100644 index 0000000..2641937 --- /dev/null +++ b/.sqlx/query-b81fe0328a6ba2c00723cd09d87ee8d7867ef30d2f3506367d9ed07d23555650.json @@ -0,0 +1,16 @@ +{ + "db_name": "PostgreSQL", + "query": "INSERT INTO ap_objects \n (\n kind,\n object,\n uuid\n )\n VALUES\n (\n $1, \n $2,\n $3\n );", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text", + "Text", + "Uuid" + ] + }, + "nullable": [] + }, + "hash": "b81fe0328a6ba2c00723cd09d87ee8d7867ef30d2f3506367d9ed07d23555650" +} diff --git a/.sqlx/query-bd3da921fe721463f998c668227208d985c2a658827ed6ff7322f2d6d07da2ae.json b/.sqlx/query-bd3da921fe721463f998c668227208d985c2a658827ed6ff7322f2d6d07da2ae.json new file mode 100644 index 0000000..8527582 --- /dev/null +++ b/.sqlx/query-bd3da921fe721463f998c668227208d985c2a658827ed6ff7322f2d6d07da2ae.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "INSERT INTO commits\n (\n object_id,\n context,\n attributed_to,\n created,\n committed,\n committed_by,\n hash,\n summary,\n description\n )\n VALUES\n (\n $1,\n $2,\n $3,\n $4,\n $5,\n $6,\n $7,\n $8,\n $9\n );", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text", + "Text", + "Text", + "Timestamptz", + "Timestamptz", + "Text", + "Text", + "Text", + "Text" + ] + }, + "nullable": [] + }, + "hash": "bd3da921fe721463f998c668227208d985c2a658827ed6ff7322f2d6d07da2ae" +} diff --git a/.sqlx/query-be35aa82dc07d53e41e6fb5d4df60bcae236e90fa4df3bd7bdff846bc7078de8.json b/.sqlx/query-be35aa82dc07d53e41e6fb5d4df60bcae236e90fa4df3bd7bdff846bc7078de8.json new file mode 100644 index 0000000..3a44b2f --- /dev/null +++ b/.sqlx/query-be35aa82dc07d53e41e6fb5d4df60bcae236e90fa4df3bd7bdff846bc7078de8.json @@ -0,0 +1,25 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n ap_objects.object\n FROM\n ap_objects\n INNER JOIN\n ap_person_objects\n ON\n ap_objects.ID = ap_person_objects.activity\n WHERE\n ap_person_objects.person_id = (SELECT ID from persons WHERE html_url = $1)\n AND\n ap_person_objects.readable && $2\n OFFSET $3 LIMIT $4;", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "object", + "type_info": "Text" + } + ], + "parameters": { + "Left": [ + "Text", + "TextArray", + "Int8", + "Int8" + ] + }, + "nullable": [ + false + ] + }, + "hash": "be35aa82dc07d53e41e6fb5d4df60bcae236e90fa4df3bd7bdff846bc7078de8" +} diff --git a/.sqlx/query-f29efc709fe6f42a21b596cd40d1234e130b716dc9faee8fba69aa24d8e10eda.json b/.sqlx/query-f29efc709fe6f42a21b596cd40d1234e130b716dc9faee8fba69aa24d8e10eda.json new file mode 100644 index 0000000..cef35f3 --- /dev/null +++ b/.sqlx/query-f29efc709fe6f42a21b596cd40d1234e130b716dc9faee8fba69aa24d8e10eda.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "INSERT INTO poll_person_checkpoints\n (person_id, activity_id)\n VALUES\n (\n (SELECT ID FROM persons WHERE html_url = $1),\n $2\n )\n ON CONFLICT\n (person_id)\n DO UPDATE SET\n activity_id = $2;", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text", + "Int4" + ] + }, + "nullable": [] + }, + "hash": "f29efc709fe6f42a21b596cd40d1234e130b716dc9faee8fba69aa24d8e10eda" +} diff --git a/.sqlx/query-f6b62a5739be59c641999f5e441e163303bfe008326e80387a119461cb881590.json b/.sqlx/query-f6b62a5739be59c641999f5e441e163303bfe008326e80387a119461cb881590.json new file mode 100644 index 0000000..e948daa --- /dev/null +++ b/.sqlx/query-f6b62a5739be59c641999f5e441e163303bfe008326e80387a119461cb881590.json @@ -0,0 +1,64 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT\n username, html_url, profile_photo, private_key, public_key, name, actor_id, preferred_username\n FROM\n persons\n WHERE\n name = $1 or username = $1;", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "username", + "type_info": "Text" + }, + { + "ordinal": 1, + "name": "html_url", + "type_info": "Text" + }, + { + "ordinal": 2, + "name": "profile_photo", + "type_info": "Text" + }, + { + "ordinal": 3, + "name": "private_key", + "type_info": "Text" + }, + { + "ordinal": 4, + "name": "public_key", + "type_info": "Text" + }, + { + "ordinal": 5, + "name": "name", + "type_info": "Text" + }, + { + "ordinal": 6, + "name": "actor_id", + "type_info": "Text" + }, + { + "ordinal": 7, + "name": "preferred_username", + "type_info": "Text" + } + ], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [ + false, + false, + true, + false, + false, + false, + false, + false + ] + }, + "hash": "f6b62a5739be59c641999f5e441e163303bfe008326e80387a119461cb881590" +} diff --git a/.sqlx/query-fa0aca169d4beaca8dc56c2076eaca9affe743fa8a10727866611a6de7bdcde2.json b/.sqlx/query-fa0aca169d4beaca8dc56c2076eaca9affe743fa8a10727866611a6de7bdcde2.json deleted file mode 100644 index c67e4b3..0000000 --- a/.sqlx/query-fa0aca169d4beaca8dc56c2076eaca9affe743fa8a10727866611a6de7bdcde2.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "SELECT uuid FROM ap_objects WHERE kind = $1 AND object = $2", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "uuid", - "type_info": "Uuid" - } - ], - "parameters": { - "Left": [ - "Text", - "Text" - ] - }, - "nullable": [ - false - ] - }, - "hash": "fa0aca169d4beaca8dc56c2076eaca9affe743fa8a10727866611a6de7bdcde2" -} diff --git a/.sqlx/query-ff360ca9aea2e0b634feb6f6dac95b7749420692cb423ccc68f8467a25f45613.json b/.sqlx/query-ff360ca9aea2e0b634feb6f6dac95b7749420692cb423ccc68f8467a25f45613.json new file mode 100644 index 0000000..9552385 --- /dev/null +++ b/.sqlx/query-ff360ca9aea2e0b634feb6f6dac95b7749420692cb423ccc68f8467a25f45613.json @@ -0,0 +1,70 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT \n object_id,\n context,\n attributed_to,\n created,\n committed,\n committed_by,\n hash,\n summary,\n description\n FROM\n commits\n WHERE\n hash = $1;", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "object_id", + "type_info": "Text" + }, + { + "ordinal": 1, + "name": "context", + "type_info": "Text" + }, + { + "ordinal": 2, + "name": "attributed_to", + "type_info": "Text" + }, + { + "ordinal": 3, + "name": "created", + "type_info": "Timestamptz" + }, + { + "ordinal": 4, + "name": "committed", + "type_info": "Timestamptz" + }, + { + "ordinal": 5, + "name": "committed_by", + "type_info": "Text" + }, + { + "ordinal": 6, + "name": "hash", + "type_info": "Text" + }, + { + "ordinal": 7, + "name": "summary", + "type_info": "Text" + }, + { + "ordinal": 8, + "name": "description", + "type_info": "Text" + } + ], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [ + false, + false, + false, + false, + false, + false, + false, + false, + true + ] + }, + "hash": "ff360ca9aea2e0b634feb6f6dac95b7749420692cb423ccc68f8467a25f45613" +} diff --git a/Cargo.lock b/Cargo.lock index b0e89bd..f774dfe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1276,6 +1276,7 @@ dependencies = [ "tracing", "tracing-actix-web", "url", + "urlencoding", "uuid", ] @@ -4066,6 +4067,12 @@ dependencies = [ "serde", ] +[[package]] +name = "urlencoding" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" + [[package]] name = "uuid" version = "1.10.0" diff --git a/Cargo.toml b/Cargo.toml index 4c90f36..a8f6204 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -45,6 +45,7 @@ reqwest-middleware = "0.2.5" reqwest_old = {package ="reqwest", features = ["json"], version = "0.11" } ##http = "1.1.0" task-local-extensions = "0.1.4" +urlencoding = "2.1.3" [dev-dependencies] diff --git a/migrations/20240523160619_persons.sql b/migrations/20240523160619_persons.sql index d4a8aff..2856947 100644 --- a/migrations/20240523160619_persons.sql +++ b/migrations/20240523160619_persons.sql @@ -1,8 +1,8 @@ CREATE TABLE IF NOT EXISTS persons ( username TEXT NOT NULL, name TEXT NOT NULL, - html_url TEXT NOT NULL, - actor_id TEXT NOT NULL, + html_url TEXT NOT NULL UNIQUE, + actor_id TEXT NOT NULL UNIQUE, private_key TEXT NOT NULL, public_key TEXT NOT NULL, profile_photo TEXT, @@ -10,3 +10,6 @@ CREATE TABLE IF NOT EXISTS persons ( preferred_username TEXT NOT NULL UNIQUE, ID SERIAL PRIMARY KEY NOT NULL ); + +CREATE UNIQUE INDEX IF NOT EXISTS persons_html_url ON persons (html_url); +CREATE UNIQUE INDEX IF NOT EXISTS persons_actor_id ON persons (actor_id); diff --git a/migrations/20240703062550_repositories.sql b/migrations/20240703062550_repositories.sql index a9ab8df..97aac86 100644 --- a/migrations/20240703062550_repositories.sql +++ b/migrations/20240703062550_repositories.sql @@ -19,3 +19,7 @@ CREATE TABLE IF NOT EXISTS repositories ( ID SERIAL PRIMARY KEY NOT NULL ); + + +CREATE UNIQUE INDEX IF NOT EXISTS repositories_html_url ON repositories (html_url); +CREATE UNIQUE INDEX IF NOT EXISTS repositories_actor_id ON repositories (actor_id); diff --git a/migrations/20240902120847_ap_objects.sql b/migrations/20240902120847_ap_objects.sql index aed2897..943d3ad 100644 --- a/migrations/20240902120847_ap_objects.sql +++ b/migrations/20240902120847_ap_objects.sql @@ -5,7 +5,7 @@ CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; CREATE TABLE IF NOT EXISTS ap_objects ( kind TEXT NOT NULL, -- URL object TEXT NOT NULL, - uuid uuid NOT NULL DEFAULT uuid_generate_v4(), + uuid uuid NOT NULL UNIQUE, timestamp timestamp with time zone DEFAULT (CURRENT_TIMESTAMP), ID SERIAL PRIMARY KEY NOT NULL ); diff --git a/migrations/20241015095812_commits.sql b/migrations/20241015095812_commits.sql new file mode 100644 index 0000000..e38e5a5 --- /dev/null +++ b/migrations/20241015095812_commits.sql @@ -0,0 +1,20 @@ +-- Add migration script here + +CREATE TABLE IF NOT EXISTS commits ( + object_id TEXT NOT NULL UNIQUE, + + context TEXT NOT NULL, + attributed_to TEXT NOT NULL, + created timestamp with time zone NOT NULL, + committed timestamp with time zone NOT NULL, + committed_by TEXT NOT NULL, + hash TEXT NOT NULL, + summary TEXT NOT NULL, + description TEXT, + UNIQUE(hash, context), + + ID SERIAL PRIMARY KEY NOT NULL +); + +CREATE UNIQUE INDEX IF NOT EXISTS commits_object_id ON commits (object_id); +CREATE UNIQUE INDEX IF NOT EXISTS commits_hash ON commits (hash); diff --git a/migrations/20241021065709_ap_person_objects.sql b/migrations/20241021065709_ap_person_objects.sql new file mode 100644 index 0000000..1077b1c --- /dev/null +++ b/migrations/20241021065709_ap_person_objects.sql @@ -0,0 +1,8 @@ +--- Add migration script here + +CREATE TABLE IF NOT EXISTS ap_person_objects ( + readable TEXT[][] NOT NULL, -- public/specific-actor + activity INTEGER REFERENCES ap_objects (ID) NOT NULL, + person_id INTEGER REFERENCES persons (ID) NOT NULL, + ID SERIAL PRIMARY KEY NOT NULL +); diff --git a/migrations/20241021070102_ap_repository_objects.sql b/migrations/20241021070102_ap_repository_objects.sql new file mode 100644 index 0000000..30d30ec --- /dev/null +++ b/migrations/20241021070102_ap_repository_objects.sql @@ -0,0 +1,6 @@ +CREATE TABLE IF NOT EXISTS ap_repository_objects ( + readable TEXT[][] NOT NULL, -- public/specific-actor + activity INTEGER REFERENCES ap_objects (ID) NOT NULL, + repository_id INTEGER REFERENCES repositories (ID) NOT NULL, + ID SERIAL PRIMARY KEY NOT NULL +); diff --git a/migrations/20241022102458_poll_person_checkpoint.sql b/migrations/20241022102458_poll_person_checkpoint.sql new file mode 100644 index 0000000..03921b9 --- /dev/null +++ b/migrations/20241022102458_poll_person_checkpoint.sql @@ -0,0 +1,5 @@ +CREATE TABLE IF NOT EXISTS poll_person_checkpoints ( + activity_id INTEGER NOT NULL, + person_id INTEGER REFERENCES persons (ID) NOT NULL UNIQUE, + ID SERIAL PRIMARY KEY NOT NULL +); diff --git a/src/federation/adapter/input/web/mod.rs b/src/federation/adapter/input/web/mod.rs index 3398a8a..f1b31f5 100644 --- a/src/federation/adapter/input/web/mod.rs +++ b/src/federation/adapter/input/web/mod.rs @@ -16,6 +16,8 @@ pub mod types; mod webfinger; pub use errors::WebJsonRepsonse; +pub use routes::APObjectIDGenerator; +pub use routes::APObjectRoutes; pub use routes::RoutesRepository; pub fn load_ctx() -> impl FnOnce(&mut web::ServiceConfig) { diff --git a/src/federation/adapter/input/web/routes.rs b/src/federation/adapter/input/web/routes.rs index a97f705..f5239d4 100644 --- a/src/federation/adapter/input/web/routes.rs +++ b/src/federation/adapter/input/web/routes.rs @@ -3,6 +3,9 @@ // SPDX-License-Identifier: AGPL-3.0-or-later use url::Url; +use uuid::Uuid; + +use crate::federation::domain::GenerateObjectID; use super::person::routes::PersonRoutes; use super::repository::routes::RepositoryRoutes; @@ -12,6 +15,7 @@ pub struct RoutesRepository { webfinger: String, pub person: PersonRoutes, pub repository: RepositoryRoutes, + pub ap_object: APObjectRoutes, } impl Default for RoutesRepository { @@ -20,6 +24,7 @@ impl Default for RoutesRepository { webfinger: "/.well-known/webfinger?resource={resource}".into(), person: PersonRoutes::default(), repository: RepositoryRoutes::default(), + ap_object: APObjectRoutes::default(), } } } @@ -29,3 +34,45 @@ impl RoutesRepository { self.webfinger.replace("{resource}", resource_iri.as_ref()) } } + +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub struct APObjectRoutes { + pub object: &'static str, + pub commit: &'static str, +} + +impl Default for APObjectRoutes { + fn default() -> Self { + Self { + object: "/federation/obejct/{uuid}".into(), + commit: "/federation/obejct/commit/{hash}".into(), + } + } +} + +impl APObjectRoutes { + pub fn object(&self, uuid: Uuid) -> String { + self.object.replace("{uuid}", &uuid.to_string()) + } + pub fn commit(&self, commit_hash: &str) -> String { + self.object.replace("{hash}", &commit_hash) + } +} + +pub struct APObjectIDGenerator { + s: crate::settings::Settings, + routes: APObjectRoutes, +} + +impl APObjectIDGenerator { + pub fn new(s: crate::settings::Settings, routes: APObjectRoutes) -> Self { + Self { s, routes } + } +} + +impl GenerateObjectID for APObjectIDGenerator { + fn generate(&self, uuid: Uuid) -> Result { + let path = self.routes.object(uuid); + crate::utils::absolute_url::absolute_url(&self.s, &path) + } +} diff --git a/src/federation/adapter/input/web/types.rs b/src/federation/adapter/input/web/types.rs index 1eaf445..450dc8c 100644 --- a/src/federation/adapter/input/web/types.rs +++ b/src/federation/adapter/input/web/types.rs @@ -7,6 +7,7 @@ use std::sync::Arc; use actix_web::web::Data; +use super::routes::APObjectIDGenerator; use super::RoutesRepository; use crate::federation::adapter::out::forge::forge_factory::FederationForgeAdapterFactoryInterface; use crate::federation::application::port::out::db::cache_activitypub_local_object::FederationOutDBCacheAPObjectObj; @@ -15,13 +16,16 @@ use crate::federation::application::port::out::db::get_remote_actor::FederationO use crate::federation::application::port::out::db::person_followers::FederationOutDBPersonFollowersObj; use crate::federation::application::port::out::db::repository_followers::FederationOutDBRepositoryFollowersObj; use crate::federation::application::port::out::db::{ - get_person::*, get_repository::*, save_person::*, save_remote_actor::*, save_repository::*, + commits::*, get_person::*, get_repository::*, poll_person_checkpoint::*, save_person::*, + save_remote_actor::*, save_repository::*, }; use crate::federation::application::port::out::forge::follow_person::FederationOutForgeFollowPersonObj; +use crate::federation::application::port::out::forge::poll_person_activities::FederationOutForgePollPersonActivitiesObj; use crate::federation::application::port::out::forge::{ parse_repository_from_url::FederationOutForgeParseRepositoryFromUrlObj, parse_username_from_url::FederationOutForgeParseUsernameFromUrlObj, }; +use crate::federation::application::services::cache_ap_local_object_service::CacheAPLocalObjectServiceObj; use crate::utils::data::Dependencies; pub(super) use crate::utils::forges::forge_repository::ForgeRepositoryInterface; use activitypub_federation::config::FederationConfig; @@ -36,6 +40,9 @@ pub type WebFederationOutDBGetRemoteActorObj = Data; pub type WebFederationOutDBDeleteRemoteActorObj = Data; pub type WebFederationOutDBRepositoryFollowersObj = Data; +pub type WebFederationOutDBPollPersonCheckpointObj = Data; +pub type WebFederationOutDBCommitsObj = Data; +//pub type WebFederationOutDBCacheAPObjectObj = Data; pub type WebFederationForgeRepositoryInterface = Data>>>; @@ -44,9 +51,13 @@ pub type WebFederationOutForgeParseUsernameFromUrlObj = pub type WebFederationOutForgeParseRepositoryFromUrlObj = Data; pub type WebFederationOutForgeFollowPersonObj = Data; +pub type WebFederationOutForgePollPersonActivitiesObj = + Data; pub type WebFederationRouteRepository = Data>; +pub type WebFederationCacheAPLocalObjectService = Data; + #[derive(Default, Clone)] pub struct FData(pub Arc); diff --git a/src/federation/adapter/mod.rs b/src/federation/adapter/mod.rs index 9e4f0f3..48df989 100644 --- a/src/federation/adapter/mod.rs +++ b/src/federation/adapter/mod.rs @@ -21,6 +21,13 @@ use self::out::forge::forge_factory::*; use self::out::forge::forgejo::ForgejoBuilder; use self::out::forge::github::GitHubBuilder; +use super::{ + application::services::cache_ap_local_object_service::{ + CacheAPLocalObjectService, CacheAPLocalObjectServiceBuilder, + }, + domain::*, +}; + #[derive(Clone)] struct Adapters { out_db_get_person_adapter: WebFederationOutDBGetPersonObj, @@ -35,7 +42,13 @@ struct Adapters { out_db_get_remote_actor_adapter: WebFederationOutDBGetRemoteActorObj, out_db_delete_remote_actor_adapter: WebFederationOutDBDeleteRemoteActorObj, + out_db_poll_person_checkpoint_adapter: WebFederationOutDBPollPersonCheckpointObj, + + out_db_commit_adapter: WebFederationOutDBCommitsObj, + forge_repository_interface: WebFederationForgeRepositoryInterface, + + cache_ap_local_obect_service: WebFederationCacheAPLocalObjectService, } impl Adapters { @@ -63,6 +76,13 @@ impl Adapters { WebFederationOutDBGetRemoteActorObj::new(Arc::new(db.clone())); let out_db_delete_remote_actor_adapter = WebFederationOutDBDeleteRemoteActorObj::new(Arc::new(db.clone())); + let out_db_cache_ap_object_adapter = + WebFederationOutDBCacheAPObjectObj::new(Arc::new(db.clone())); + + let out_db_commit_adapter = WebFederationOutDBCommitsObj::new(Arc::new(db.clone())); + + let out_db_poll_person_checkpoint_adapter = + WebFederationOutDBPollPersonCheckpointObj::new(Arc::new(db.clone())); let forgejo: Arc = Arc::new(ForgejoAdapterFactory::new( @@ -105,6 +125,23 @@ impl Adapters { WebFederationForgeRepositoryInterface::new(f) }; + let cache_ap_local_obect_service = { + let object_id_generator: FederationGenerateObjectID = + Arc::new(input::web::APObjectIDGenerator::new( + settings.clone(), + input::web::RoutesRepository::default().ap_object, + )); + WebFederationCacheAPLocalObjectService::new(Arc::new( + CacheAPLocalObjectServiceBuilder::default() + .out_db_cache_ap_local_object_adapter( + out_db_cache_ap_object_adapter.as_ref().clone(), + ) + .object_id_generator(object_id_generator) + .build() + .unwrap(), + )) + }; + Self { out_db_get_person_adapter, out_db_save_person_adapter, @@ -116,13 +153,24 @@ impl Adapters { out_db_save_remote_actor_adapter, out_db_delete_remote_actor_adapter, out_db_repository_follower_adapter, + out_db_poll_person_checkpoint_adapter, + out_db_commit_adapter, + // out_db_cache_ap_object_adapter, forge_repository_interface, + + cache_ap_local_obect_service, } } } pub async fn federation_config(pool: PgPool, settings: &settings::Settings) -> WebFederationConfig { let adapters = Adapters::new(pool, settings); + let object_id_generator: FederationGenerateObjectID = + Arc::new(input::web::APObjectIDGenerator::new( + settings.clone(), + input::web::RoutesRepository::default().ap_object, + )); + // let object_id_generator: fn(uuid: Uuid) -> Result = object_id_generator.generate; let mut data = Dependencies::default(); data.insert(adapters.out_db_get_person_adapter.clone()); @@ -135,14 +183,20 @@ pub async fn federation_config(pool: PgPool, settings: &settings::Settings) -> W data.insert(adapters.out_db_get_remote_actor_adapter.clone()); data.insert(adapters.out_db_save_remote_actor_adapter.clone()); data.insert(adapters.forge_repository_interface.clone()); - data.insert(adapters.out_db_delete_remote_actor_adapter); + data.insert(adapters.out_db_delete_remote_actor_adapter.clone()); + data.insert(adapters.out_db_cache_ap_object_adapter.clone()); + data.insert(adapters.out_db_poll_person_checkpoint_adapter.clone()); + data.insert(adapters.out_db_commit_adapter.clone()); data.insert(settings.clone()); data.insert(WebSettings::new(settings.clone())); data.insert(input::web::RoutesRepository::default()); + data.insert(WebFederationRouteRepository::new(Arc::new( input::web::RoutesRepository::default(), ))); + data.insert(adapters.cache_ap_local_obect_service.clone()); + let data = FData(Arc::new(data)); actix_web::web::Data::new( @@ -182,8 +236,12 @@ pub fn load_adapters( cfg.app_data(adapters.out_db_save_remote_actor_adapter.clone()); cfg.app_data(adapters.out_db_delete_remote_actor_adapter.clone()); cfg.app_data(adapters.out_db_repository_follower_adapter.clone()); + cfg.app_data(adapters.out_db_poll_person_checkpoint_adapter.clone()); + cfg.app_data(adapters.out_db_commit_adapter.clone()); cfg.app_data(adapters.forge_repository_interface); + + cfg.app_data(adapters.cache_ap_local_obect_service.clone()); }; Box::new(f) diff --git a/src/federation/adapter/out/db/postgres/errors.rs b/src/federation/adapter/out/db/postgres/errors.rs index b093525..7752c6e 100644 --- a/src/federation/adapter/out/db/postgres/errors.rs +++ b/src/federation/adapter/out/db/postgres/errors.rs @@ -2,7 +2,7 @@ // // SPDX-License-Identifier: AGPL-3.0-or-later -//use std::borrow::Cow; +use std::borrow::Cow; use sqlx::Error as SqlxError; @@ -11,18 +11,19 @@ use crate::federation::application::port::out::db::errors::FederationOutDBPortEr impl From for FederationOutDBPortError { fn from(e: SqlxError) -> Self { println!("[postgres] err: {}", e); - // if let SqlxError::Database(err) = e { - // if err.code() == Some(Cow::from("23505")) { - // let msg = err.message(); - // if msg.contains("oauth_state_state_key") { - // return Self::DuplicateState; - // } else if msg.contains("oauth_access_token_username_oauth_provider_key") { - // return Self::DuplicateAccessToken; - // } else { - // println!("{msg}"); - // } - // } - // } + if let SqlxError::Database(err) = e { + if err.code() == Some(Cow::from("23505")) { + let msg = err.message(); + if msg.contains("ap_objects_uuid_key") { + return Self::CacheAPObjectIDExists; + } + // } else if msg.contains("oauth_access_token_username_oauth_provider_key") { + // return Self::DuplicateAccessToken; + // } else { + // println!("{msg}"); + // } + } + } Self::InternalError } } diff --git a/src/federation/adapter/out/db/postgres/mod.rs b/src/federation/adapter/out/db/postgres/mod.rs index 6826782..e05b773 100644 --- a/src/federation/adapter/out/db/postgres/mod.rs +++ b/src/federation/adapter/out/db/postgres/mod.rs @@ -12,9 +12,11 @@ mod save_person; mod save_repository; // ActivityPub mod cache_activitypub_local_object; +mod commits; mod delete_remote_actor; mod get_remote_actor; mod person_followers; +mod poll_person_checkpoint; mod repository_followers; mod save_remote_actor; diff --git a/src/federation/application/port/out/db/errors.rs b/src/federation/application/port/out/db/errors.rs index bf30ced..8c8efd5 100644 --- a/src/federation/application/port/out/db/errors.rs +++ b/src/federation/application/port/out/db/errors.rs @@ -10,4 +10,5 @@ pub type FederationOutDBPortResult = Result; #[derive(Debug, Display, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)] pub enum FederationOutDBPortError { InternalError, + CacheAPObjectIDExists, } diff --git a/src/federation/application/port/out/db/mod.rs b/src/federation/application/port/out/db/mod.rs index 6ab84e6..cbdfb37 100644 --- a/src/federation/application/port/out/db/mod.rs +++ b/src/federation/application/port/out/db/mod.rs @@ -3,12 +3,14 @@ // SPDX-License-Identifier: AGPL-3.0-or-later pub mod cache_activitypub_local_object; +pub mod commits; pub mod delete_remote_actor; pub mod errors; pub mod get_person; pub mod get_remote_actor; pub mod get_repository; pub mod person_followers; +pub mod poll_person_checkpoint; pub mod repository_followers; pub mod save_person; pub mod save_remote_actor; diff --git a/src/federation/application/port/out/forge/mod.rs b/src/federation/application/port/out/forge/mod.rs index bfbb90f..7581ad9 100644 --- a/src/federation/application/port/out/forge/mod.rs +++ b/src/federation/application/port/out/forge/mod.rs @@ -11,5 +11,7 @@ pub mod parse_username_from_url; //pub mod generate_repo_url; pub mod follow_person; pub mod follow_repository; +pub mod poll_person_activities; pub mod unfollow_person; pub mod unfollow_repository; +//pub mod get_person_feed;