feat: services to create and retrieve system actor
This commit is contained in:
parent
4babf95810
commit
412c4cbc73
9 changed files with 289 additions and 8 deletions
|
@ -16,6 +16,7 @@ pub mod types;
|
|||
mod webfinger;
|
||||
|
||||
pub use errors::WebJsonRepsonse;
|
||||
pub use routes::system_actor::*;
|
||||
pub use routes::APObjectIDGenerator;
|
||||
pub use routes::APObjectRoutes;
|
||||
pub use routes::RoutesRepository;
|
||||
|
|
|
@ -16,6 +16,7 @@ pub struct RoutesRepository {
|
|||
pub person: PersonRoutes,
|
||||
pub repository: RepositoryRoutes,
|
||||
pub ap_object: APObjectRoutes,
|
||||
pub system_actor: system_actor::SystemActorRoutes,
|
||||
}
|
||||
|
||||
impl Default for RoutesRepository {
|
||||
|
@ -25,6 +26,7 @@ impl Default for RoutesRepository {
|
|||
person: PersonRoutes::default(),
|
||||
repository: RepositoryRoutes::default(),
|
||||
ap_object: APObjectRoutes::default(),
|
||||
system_actor: system_actor::SystemActorRoutes::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -76,3 +78,68 @@ impl GenerateObjectID for APObjectIDGenerator {
|
|||
crate::utils::absolute_url::absolute_url(&self.s, &path)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) mod system_actor {
|
||||
use super::*;
|
||||
use crate::federation::domain::system_actor::GenerateSystemActorRoutes;
|
||||
use crate::{settings::Settings, utils::forges::*};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct SystemActorRoutes {
|
||||
actor: String,
|
||||
inbox: String,
|
||||
outbox: String,
|
||||
followers: String,
|
||||
}
|
||||
|
||||
impl Default for SystemActorRoutes {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
actor: "/system/{username}".into(),
|
||||
inbox: "/system/{username}/inbox".into(),
|
||||
outbox: "/system/{username}/outbox".into(),
|
||||
followers: "/system/{username}/followers".into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SystemActorRoutes {
|
||||
pub fn actor(&self, username: &str) -> String {
|
||||
self.actor.replace("{username}", username)
|
||||
}
|
||||
|
||||
pub fn inbox(&self, username: &str) -> String {
|
||||
self.inbox.replace("{username}", username)
|
||||
}
|
||||
|
||||
pub fn outbox(&self, username: &str) -> String {
|
||||
self.outbox.replace("{username}", username)
|
||||
}
|
||||
|
||||
pub fn followers(&self, username: &str) -> String {
|
||||
self.followers.replace("{username}", username)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SystemActorRouteGenerator {
|
||||
s: crate::settings::Settings,
|
||||
routes: SystemActorRoutes,
|
||||
}
|
||||
|
||||
impl SystemActorRouteGenerator {
|
||||
pub fn new(s: crate::settings::Settings, routes: SystemActorRoutes) -> Self {
|
||||
Self { s, routes }
|
||||
}
|
||||
}
|
||||
|
||||
impl GenerateSystemActorRoutes for SystemActorRouteGenerator {
|
||||
fn generate_actor_id(&self, username: &str) -> Result<Url, url::ParseError> {
|
||||
let path = self.routes.actor(username);
|
||||
crate::utils::absolute_url::absolute_url(&self.s, &path)
|
||||
}
|
||||
fn generate_html_url(&self, username: &str) -> Result<Url, url::ParseError> {
|
||||
let path = self.routes.actor(username);
|
||||
crate::utils::absolute_url::absolute_url(&self.s, &path)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ use crate::federation::application::port::out::forge::{
|
|||
parse_username_from_url::FederationOutForgeParseUsernameFromUrlObj,
|
||||
};
|
||||
use crate::federation::application::services::cache_ap_local_object_service::CacheAPLocalObjectServiceObj;
|
||||
use crate::federation::application::services::get_system_actor_service::GetSystemActorServiceObj;
|
||||
use crate::utils::data::Dependencies;
|
||||
pub(super) use crate::utils::forges::forge_repository::ForgeRepositoryInterface;
|
||||
use activitypub_federation::config::FederationConfig;
|
||||
|
@ -57,6 +58,7 @@ pub type WebFederationOutForgePollPersonActivitiesObj =
|
|||
pub type WebFederationRouteRepository = Data<Arc<RoutesRepository>>;
|
||||
|
||||
pub type WebFederationCacheAPLocalObjectService = Data<CacheAPLocalObjectServiceObj>;
|
||||
pub type WebFederationGetSystemActorService = Data<GetSystemActorServiceObj>;
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
pub struct FData(pub Arc<Dependencies>);
|
||||
|
|
|
@ -22,8 +22,12 @@ use self::out::forge::forgejo::ForgejoBuilder;
|
|||
use self::out::forge::github::GitHubBuilder;
|
||||
|
||||
use super::{
|
||||
application::services::cache_ap_local_object_service::{
|
||||
CacheAPLocalObjectService, CacheAPLocalObjectServiceBuilder,
|
||||
application::services::{
|
||||
cache_ap_local_object_service::{
|
||||
CacheAPLocalObjectService, CacheAPLocalObjectServiceBuilder,
|
||||
},
|
||||
get_system_actor_service::*,
|
||||
init_system_actor_service::*,
|
||||
},
|
||||
domain::*,
|
||||
};
|
||||
|
@ -49,6 +53,7 @@ struct Adapters {
|
|||
forge_repository_interface: WebFederationForgeRepositoryInterface,
|
||||
|
||||
cache_ap_local_obect_service: WebFederationCacheAPLocalObjectService,
|
||||
get_system_actor_service: WebFederationGetSystemActorService,
|
||||
}
|
||||
|
||||
impl Adapters {
|
||||
|
@ -142,6 +147,34 @@ impl Adapters {
|
|||
))
|
||||
};
|
||||
|
||||
let get_system_actor_service = {
|
||||
let out_db_system_actor_adapter = Arc::new(db.clone());
|
||||
|
||||
let init_system_actor_service = {
|
||||
let system_actor_routes_generator =
|
||||
Arc::new(input::web::SystemActorRouteGenerator::new(
|
||||
settings.clone(),
|
||||
input::web::RoutesRepository::default().system_actor,
|
||||
));
|
||||
|
||||
Arc::new(
|
||||
InitSystemActorServiceBuilder::default()
|
||||
.out_db_system_actor_adapter(out_db_system_actor_adapter.clone())
|
||||
.system_actor_routes_generator(system_actor_routes_generator)
|
||||
.build()
|
||||
.unwrap(),
|
||||
)
|
||||
};
|
||||
|
||||
WebFederationGetSystemActorService::new(Arc::new(
|
||||
GetSystemActorServiceBuilder::default()
|
||||
.out_db_system_actor_adapter(out_db_system_actor_adapter.clone())
|
||||
.init_system_actor_service(init_system_actor_service.clone())
|
||||
.build()
|
||||
.unwrap(),
|
||||
))
|
||||
};
|
||||
|
||||
Self {
|
||||
out_db_get_person_adapter,
|
||||
out_db_save_person_adapter,
|
||||
|
@ -159,18 +192,13 @@ impl Adapters {
|
|||
forge_repository_interface,
|
||||
|
||||
cache_ap_local_obect_service,
|
||||
get_system_actor_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<Url, url::ParseError> = object_id_generator.generate;
|
||||
|
||||
let mut data = Dependencies::default();
|
||||
data.insert(adapters.out_db_get_person_adapter.clone());
|
||||
|
@ -196,6 +224,7 @@ pub async fn federation_config(pool: PgPool, settings: &settings::Settings) -> W
|
|||
)));
|
||||
|
||||
data.insert(adapters.cache_ap_local_obect_service.clone());
|
||||
data.insert(adapters.get_system_actor_service.clone());
|
||||
|
||||
let data = FData(Arc::new(data));
|
||||
|
||||
|
@ -242,6 +271,7 @@ pub fn load_adapters(
|
|||
cfg.app_data(adapters.forge_repository_interface);
|
||||
|
||||
cfg.app_data(adapters.cache_ap_local_obect_service.clone());
|
||||
cfg.app_data(adapters.get_system_actor_service.clone());
|
||||
};
|
||||
|
||||
Box::new(f)
|
||||
|
|
|
@ -19,6 +19,7 @@ mod person_followers;
|
|||
mod poll_person_checkpoint;
|
||||
mod repository_followers;
|
||||
mod save_remote_actor;
|
||||
mod system_actor;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct DBOutPostgresAdapter {
|
||||
|
|
|
@ -15,3 +15,4 @@ pub mod repository_followers;
|
|||
pub mod save_person;
|
||||
pub mod save_remote_actor;
|
||||
pub mod save_repository;
|
||||
pub mod system_actor;
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
// SPDX-FileCopyrightText: 2024 Aravinth Manivannan <realaravinth@batsense.net>
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
use derive_builder::Builder;
|
||||
use system_actor::SystemActorBuilder;
|
||||
use url::Url;
|
||||
|
||||
use super::errors::*;
|
||||
use super::init_system_actor_service::*;
|
||||
use crate::federation::application::port::out::db::system_actor::*;
|
||||
use crate::federation::domain::{system_actor::*, *};
|
||||
|
||||
#[async_trait::async_trait]
|
||||
pub trait GetSystemActorUseCase: Send + Sync {
|
||||
async fn get_system_actor(&self) -> FederationServiceResult<SystemActor>;
|
||||
}
|
||||
|
||||
#[derive(Builder, Clone)]
|
||||
pub struct GetSystemActorService {
|
||||
out_db_system_actor_adapter: FederationOutDBSystemActorObj,
|
||||
init_system_actor_service: InitSystemActorServiceObj,
|
||||
}
|
||||
|
||||
pub type GetSystemActorServiceObj = std::sync::Arc<dyn GetSystemActorUseCase>;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl GetSystemActorUseCase for GetSystemActorService {
|
||||
async fn get_system_actor(&self) -> FederationServiceResult<SystemActor> {
|
||||
let system_actor = match self
|
||||
.out_db_system_actor_adapter
|
||||
.get_from_preferred_username(SYSTEM_ACTOR_PREFERRED_USERNAME)
|
||||
.await?
|
||||
{
|
||||
Some(system_actor) => system_actor,
|
||||
None => self.init_system_actor_service.init_system_actor().await?,
|
||||
};
|
||||
|
||||
Ok(system_actor)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
use crate::tests::bdd::*;
|
||||
|
||||
#[actix_rt::test]
|
||||
async fn test_service_get_from_db() {
|
||||
// retrieved from DB
|
||||
let s = GetSystemActorServiceBuilder::default()
|
||||
.out_db_system_actor_adapter(mock_get_system_actor_from_preferred_username(
|
||||
IS_CALLED_ONLY_ONCE,
|
||||
))
|
||||
.init_system_actor_service(mock_init_system_actor_service(IS_NEVER_CALLED))
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
let resp = s.get_system_actor().await.unwrap();
|
||||
assert_eq!(resp.preferred_username(), SYSTEM_ACTOR_PREFERRED_USERNAME);
|
||||
assert!(resp.keys().savable());
|
||||
}
|
||||
|
||||
#[actix_rt::test]
|
||||
async fn test_service_no_db_generate_and_save() {
|
||||
// doesn't exist, so generating and saving
|
||||
let s = GetSystemActorServiceBuilder::default()
|
||||
.out_db_system_actor_adapter(
|
||||
mock_get_system_actor_from_preferred_username_returns_none(IS_CALLED_ONLY_ONCE),
|
||||
)
|
||||
.init_system_actor_service(mock_init_system_actor_service(IS_CALLED_ONLY_ONCE))
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
let resp = s.get_system_actor().await.unwrap();
|
||||
assert_eq!(resp.preferred_username(), SYSTEM_ACTOR_PREFERRED_USERNAME);
|
||||
assert!(resp.keys().savable());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
// SPDX-FileCopyrightText: 2024 Aravinth Manivannan <realaravinth@batsense.net>
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
//use actix_rt::(;
|
||||
use derive_builder::Builder;
|
||||
use derive_getters::Getters;
|
||||
use mockall::predicate::*;
|
||||
use mockall::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use system_actor::SystemActorBuilder;
|
||||
#[allow(unused_imports)]
|
||||
#[cfg(test)]
|
||||
pub use tests::*;
|
||||
use url::Url;
|
||||
|
||||
use super::errors::*;
|
||||
use crate::federation::application::port::out::db::system_actor::*;
|
||||
use crate::federation::domain::{system_actor::*, *};
|
||||
|
||||
#[automock]
|
||||
#[async_trait::async_trait]
|
||||
pub trait InitSystemActorUseCase: Send + Sync {
|
||||
async fn init_system_actor(&self) -> FederationServiceResult<SystemActor>;
|
||||
}
|
||||
|
||||
pub type InitSystemActorServiceObj = std::sync::Arc<dyn InitSystemActorUseCase>;
|
||||
|
||||
#[derive(Builder, Clone)]
|
||||
pub struct InitSystemActorService {
|
||||
out_db_system_actor_adapter: FederationOutDBSystemActorObj,
|
||||
system_actor_routes_generator: FederationGenerateSystemActorRoutes,
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl InitSystemActorUseCase for InitSystemActorService {
|
||||
async fn init_system_actor(&self) -> FederationServiceResult<SystemActor> {
|
||||
let actor_id = self
|
||||
.system_actor_routes_generator
|
||||
.generate_actor_id(SYSTEM_ACTOR_PREFERRED_USERNAME)
|
||||
.unwrap();
|
||||
let html_url = self
|
||||
.system_actor_routes_generator
|
||||
.generate_html_url(SYSTEM_ACTOR_PREFERRED_USERNAME)
|
||||
.unwrap();
|
||||
|
||||
let mut system_actor = SystemActorBuilder::default()
|
||||
.preferred_username(SYSTEM_ACTOR_PREFERRED_USERNAME.into())
|
||||
.html_url(html_url)
|
||||
.actor_id(actor_id)
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
system_actor.generate_keys();
|
||||
|
||||
self.out_db_system_actor_adapter
|
||||
.create(&system_actor)
|
||||
.await?;
|
||||
|
||||
Ok(system_actor)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
use crate::tests::bdd::*;
|
||||
|
||||
pub fn mock_init_system_actor_service(times: Option<usize>) -> InitSystemActorServiceObj {
|
||||
let mut m = MockInitSystemActorUseCase::new();
|
||||
let mut system_actor = SystemActor::default();
|
||||
system_actor.generate_keys();
|
||||
if let Some(times) = times {
|
||||
m.expect_init_system_actor()
|
||||
.times(times)
|
||||
.return_const(Ok(system_actor));
|
||||
} else {
|
||||
m.expect_init_system_actor().return_const(Ok(system_actor));
|
||||
}
|
||||
|
||||
std::sync::Arc::new(m)
|
||||
}
|
||||
|
||||
#[actix_rt::test]
|
||||
async fn test_service() {
|
||||
let s = InitSystemActorServiceBuilder::default()
|
||||
.out_db_system_actor_adapter(mock_system_actor_create(IS_CALLED_ONLY_ONCE))
|
||||
.system_actor_routes_generator(mock_generate_system_actor_routes(IS_CALLED_ONLY_ONCE))
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
let resp = s.init_system_actor().await.unwrap();
|
||||
assert!(resp.keys().savable());
|
||||
assert_eq!(resp.preferred_username(), SYSTEM_ACTOR_PREFERRED_USERNAME);
|
||||
}
|
||||
}
|
|
@ -22,6 +22,8 @@ pub mod get_person_follower_list_service;
|
|||
pub mod get_person_from_follow_init_activity_id;
|
||||
pub mod get_remote_actor_service;
|
||||
pub mod get_repository_from_follow_init_activity_id;
|
||||
pub mod get_system_actor_service;
|
||||
pub mod init_system_actor_service;
|
||||
pub mod poll_person_service;
|
||||
pub mod resolve_actor_type_service;
|
||||
pub mod save_remote_actor_service;
|
||||
|
|
Loading…
Reference in a new issue