feat: unfollow repository (stub), resolve actor in Undo, and hook Undo in Repository inbox handler #88
5 changed files with 143 additions and 12 deletions
|
@ -14,11 +14,11 @@ mod outbox;
|
|||
pub mod routes;
|
||||
mod utils;
|
||||
|
||||
mod accept_activity;
|
||||
mod delete_activity;
|
||||
pub mod accept_activity;
|
||||
pub mod delete_activity;
|
||||
mod follow_activity;
|
||||
mod remote_actor;
|
||||
mod undo_activity;
|
||||
pub mod undo_activity;
|
||||
|
||||
pub use super::errors::WebJsonRepsonse;
|
||||
|
||||
|
|
|
@ -12,8 +12,12 @@ use serde::{Deserialize, Serialize};
|
|||
use url::Url;
|
||||
|
||||
use crate::federation::adapter::input::web::types::*;
|
||||
use crate::federation::application::services::errors::FederationServiceError;
|
||||
use crate::federation::application::services::unfollow_person_service::*;
|
||||
use crate::federation::application::services::{
|
||||
errors::*,
|
||||
unfollow_person_service::{command::*, *},
|
||||
unfollow_repository_service::{command::*, *},
|
||||
};
|
||||
use crate::federation::domain::*;
|
||||
|
||||
#[derive(Clone, Getters, Builder, Debug, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
|
@ -49,6 +53,34 @@ impl ActivityHandler for Undo {
|
|||
async fn receive(self, data: &APData<Self::DataType>) -> Result<(), Self::Error> {
|
||||
// NOTE: Currently, only Undo supported activity is following. Improve resolving underlying
|
||||
// actor, as new stuff is implemented
|
||||
|
||||
self.unfollow_person(data).await?;
|
||||
self.unfollow_repository(data).await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Undo {
|
||||
async fn unfollow_repository(&self, data: &APData<FData>) -> FederationServiceResult<()> {
|
||||
let out_db_repository_followers_adapter = data
|
||||
.get::<WebFederationOutDBRepositoryFollowersObj>()
|
||||
.unwrap()
|
||||
.clone();
|
||||
|
||||
let s = UnfollowRepositoryServiceBuilder::default()
|
||||
.out_db_repository_followers_adapter(
|
||||
out_db_repository_followers_adapter.as_ref().clone(),
|
||||
)
|
||||
.build()
|
||||
.unwrap();
|
||||
s.unfollow_repository(UnfollowRepositoryCommand::new_command(
|
||||
self.actor().clone(),
|
||||
self.object().clone(),
|
||||
))
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
async fn unfollow_person(&self, data: &APData<FData>) -> FederationServiceResult<()> {
|
||||
let out_db_person_followers_adapter = data
|
||||
.get::<WebFederationOutDBPersonFollowersObj>()
|
||||
.unwrap()
|
||||
|
@ -58,12 +90,11 @@ impl ActivityHandler for Undo {
|
|||
.out_db_person_followers_adapter(out_db_person_followers_adapter.as_ref().clone())
|
||||
.build()
|
||||
.unwrap();
|
||||
s.unfollow_person(command::UnfollowPersonCommand::new_command(
|
||||
s.unfollow_person(UnfollowPersonCommand::new_command(
|
||||
self.actor().clone(),
|
||||
self.object().clone(),
|
||||
))
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -76,8 +107,11 @@ mod tests {
|
|||
|
||||
use super::*;
|
||||
use crate::{
|
||||
federation::application::port::out::db::person_followers::*,
|
||||
tests::bdd::IS_CALLED_ONLY_ONCE, utils::data::Dependencies,
|
||||
federation::application::port::out::db::{
|
||||
person_followers::*, repository_followers::mock_follow_repository_delete,
|
||||
},
|
||||
tests::bdd::IS_CALLED_ONLY_ONCE,
|
||||
utils::data::Dependencies,
|
||||
};
|
||||
|
||||
fn get_undo() -> Undo {
|
||||
|
@ -86,13 +120,24 @@ mod tests {
|
|||
|
||||
id: Url::parse("https://example.com/actor#undo").unwrap(),
|
||||
actor: Url::parse("https://example.com/actor").unwrap(),
|
||||
object: Url::parse("https://example.com/actor").unwrap(),
|
||||
object: Url::parse("https://example.com/activity").unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
#[actix_rt::test]
|
||||
async fn test_undo_activity_verify() {
|
||||
let settings = crate::settings::Settings::new().unwrap();
|
||||
let mut settings = crate::settings::Settings::new().unwrap();
|
||||
|
||||
{
|
||||
let p = Person::default();
|
||||
let mut forge_url = p.html_url().clone();
|
||||
forge_url.set_path("");
|
||||
|
||||
settings.forges.forgejo.url = forge_url.clone();
|
||||
settings.forges.github.url = forge_url.clone();
|
||||
settings.server.domain = p.actor_id().host_str().unwrap().to_owned();
|
||||
}
|
||||
|
||||
let data = FederationConfig::builder()
|
||||
.domain(settings.server.domain.clone())
|
||||
.app_data(FData(Arc::new(Dependencies::new())))
|
||||
|
@ -147,13 +192,17 @@ mod tests {
|
|||
}
|
||||
|
||||
#[actix_rt::test]
|
||||
async fn test_undo_activity_receive() {
|
||||
async fn test_undo_activity_receive_unfollow_person_repository() {
|
||||
let settings = crate::settings::Settings::new().unwrap();
|
||||
|
||||
let mut deps = Dependencies::new();
|
||||
deps.insert(WebFederationOutDBPersonFollowersObj::new(
|
||||
mock_follow_person_delete(IS_CALLED_ONLY_ONCE),
|
||||
));
|
||||
deps.insert(WebFederationOutDBRepositoryFollowersObj::new(
|
||||
mock_follow_repository_delete(IS_CALLED_ONLY_ONCE),
|
||||
));
|
||||
|
||||
let data = FederationConfig::builder()
|
||||
.domain(settings.server.domain.clone())
|
||||
.app_data(FData(Arc::new(deps)))
|
||||
|
|
|
@ -72,6 +72,7 @@ pub struct ForgeFedRepository {
|
|||
#[enum_delegate::implement(ActivityHandler)]
|
||||
pub enum RepositoryAcceptedActivities {
|
||||
Follow(crate::federation::domain::follow_activity::Follow),
|
||||
Undo(crate::federation::adapter::input::web::person::undo_activity::Undo),
|
||||
}
|
||||
|
||||
impl ForgeFedRepositoryBuilder {
|
||||
|
|
|
@ -21,3 +21,4 @@ pub mod get_remote_actor_service;
|
|||
pub mod resolve_actor_type_service;
|
||||
pub mod save_remote_actor_service;
|
||||
pub mod unfollow_person_service;
|
||||
pub mod unfollow_repository_service;
|
||||
|
|
|
@ -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 derive_getters::Getters;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use url::Url;
|
||||
|
||||
use super::errors::*;
|
||||
use crate::federation::application::port::out::db::repository_followers::*;
|
||||
|
||||
pub mod command {
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug, Getters, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct UnfollowRepositoryCommand {
|
||||
follower: Url,
|
||||
init_activity_id: Url,
|
||||
}
|
||||
|
||||
impl UnfollowRepositoryCommand {
|
||||
pub fn new_command(follower: Url, init_activity_id: Url) -> Self {
|
||||
Self {
|
||||
follower,
|
||||
init_activity_id,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
pub trait UnfollowRepositoryUseCase: Send + Sync {
|
||||
async fn unfollow_repository(
|
||||
&self,
|
||||
cmd: command::UnfollowRepositoryCommand,
|
||||
) -> FederationServiceResult<()>;
|
||||
}
|
||||
|
||||
#[derive(Builder, Clone)]
|
||||
pub struct UnfollowRepositoryService {
|
||||
out_db_repository_followers_adapter: FederationOutDBRepositoryFollowersObj,
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl UnfollowRepositoryUseCase for UnfollowRepositoryService {
|
||||
async fn unfollow_repository(
|
||||
&self,
|
||||
cmd: command::UnfollowRepositoryCommand,
|
||||
) -> FederationServiceResult<()> {
|
||||
self.out_db_repository_followers_adapter
|
||||
.delete(cmd.follower(), cmd.init_activity_id())
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
use crate::tests::bdd::*;
|
||||
|
||||
#[actix_rt::test]
|
||||
async fn test_service() {
|
||||
let follower_url = Url::parse("https://git.example.com/foo").unwrap();
|
||||
let init_activity_id = Url::parse("https://ap.example.com/bar").unwrap();
|
||||
let cmd = command::UnfollowRepositoryCommand::new_command(
|
||||
follower_url.clone(),
|
||||
init_activity_id.clone(),
|
||||
);
|
||||
// retrieved from DB
|
||||
let s = UnfollowRepositoryServiceBuilder::default()
|
||||
.out_db_repository_followers_adapter(mock_follow_repository_delete(IS_CALLED_ONLY_ONCE))
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
s.unfollow_repository(cmd.clone()).await.unwrap();
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue