mirror of
https://github.com/versia-pub/activitypub.git
synced 2025-12-06 06:38:20 +01:00
feat: Add generate_follow_accept_id function to utils.rs and follow_manually endpoint to main.rs
This commit is contained in:
parent
3ebe83c52f
commit
36d10f774a
|
|
@ -1,12 +1,20 @@
|
||||||
use activitypub_federation::{config::Data, fetch::object_id::ObjectId, traits::ActivityHandler};
|
use activitypub_federation::{
|
||||||
use activitystreams_kinds::activity::FollowType;
|
activity_sending::SendActivityTask,
|
||||||
|
config::Data,
|
||||||
|
fetch::object_id::ObjectId,
|
||||||
|
protocol::context::WithContext,
|
||||||
|
traits::{ActivityHandler, Actor, Object},
|
||||||
|
};
|
||||||
|
use activitystreams_kinds::activity::{AcceptType, FollowType};
|
||||||
use sea_orm::{ActiveModelTrait, Set};
|
use sea_orm::{ActiveModelTrait, Set};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
database::StateHandle,
|
database::StateHandle,
|
||||||
entities::{follow_relation, prelude::FollowRelation, user},
|
entities::{follow_relation, post, user},
|
||||||
|
error,
|
||||||
|
utils::{generate_follow_accept_id, generate_object_id},
|
||||||
DB,
|
DB,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -19,6 +27,73 @@ pub struct Follow {
|
||||||
id: Url,
|
id: Url,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Follow {
|
||||||
|
pub async fn send(
|
||||||
|
local_user: ObjectId<user::Model>,
|
||||||
|
followee: ObjectId<user::Model>,
|
||||||
|
inbox: Url,
|
||||||
|
data: &Data<StateHandle>,
|
||||||
|
) -> Result<(), error::Error> {
|
||||||
|
print!("Sending follow request to {}", &followee);
|
||||||
|
let create = Follow {
|
||||||
|
actor: local_user.clone(),
|
||||||
|
object: followee.clone(),
|
||||||
|
kind: FollowType::Follow,
|
||||||
|
id: generate_object_id(data.domain())?,
|
||||||
|
};
|
||||||
|
let create_with_context = WithContext::new_default(create);
|
||||||
|
let sends = SendActivityTask::prepare(
|
||||||
|
&create_with_context,
|
||||||
|
&data.local_user().await?,
|
||||||
|
vec![inbox],
|
||||||
|
data,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
for send in sends {
|
||||||
|
send.sign_and_send(data).await?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize, Debug)]
|
||||||
|
pub struct Accept {
|
||||||
|
actor: ObjectId<user::Model>,
|
||||||
|
object: Follow,
|
||||||
|
#[serde(rename = "type")]
|
||||||
|
kind: AcceptType,
|
||||||
|
id: Url,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Accept {
|
||||||
|
pub async fn send(
|
||||||
|
follow_relation: follow_relation::Model,
|
||||||
|
follow_req: Follow,
|
||||||
|
inbox: Url,
|
||||||
|
data: &Data<StateHandle>,
|
||||||
|
) -> Result<(), error::Error> {
|
||||||
|
print!("Sending accept to {}", &follow_relation.follower_id);
|
||||||
|
let create = Accept {
|
||||||
|
actor: follow_req.object.clone(),
|
||||||
|
object: follow_req,
|
||||||
|
kind: AcceptType::Accept,
|
||||||
|
id: generate_follow_accept_id(data.domain(), follow_relation.id)?,
|
||||||
|
};
|
||||||
|
let create_with_context = WithContext::new_default(create);
|
||||||
|
let sends = SendActivityTask::prepare(
|
||||||
|
&create_with_context,
|
||||||
|
&data.local_user().await?,
|
||||||
|
vec![inbox],
|
||||||
|
data,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
for send in sends {
|
||||||
|
send.sign_and_send(data).await?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl ActivityHandler for Follow {
|
impl ActivityHandler for Follow {
|
||||||
type DataType = StateHandle;
|
type DataType = StateHandle;
|
||||||
|
|
@ -37,17 +112,51 @@ impl ActivityHandler for Follow {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn receive(self, data: &Data<Self::DataType>) -> Result<(), Self::Error> {
|
async fn receive(self, data: &Data<Self::DataType>) -> Result<(), Self::Error> {
|
||||||
let local_user = self.object.dereference(data).await?;
|
accept_follow(self, data).await?;
|
||||||
let follower = self.actor.dereference(data).await?;
|
|
||||||
save_follow(local_user, follower).await?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl ActivityHandler for Accept {
|
||||||
|
type DataType = StateHandle;
|
||||||
|
type Error = crate::error::Error;
|
||||||
|
|
||||||
|
fn id(&self) -> &Url {
|
||||||
|
&self.id
|
||||||
|
}
|
||||||
|
|
||||||
|
fn actor(&self) -> &Url {
|
||||||
|
self.actor.inner()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn verify(&self, data: &Data<Self::DataType>) -> Result<(), Self::Error> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn receive(self, data: &Data<Self::DataType>) -> Result<(), Self::Error> {
|
||||||
|
let user = self.actor.dereference(data).await?;
|
||||||
|
let follower = self.object.actor.dereference(data).await?;
|
||||||
|
save_follow(user, follower).await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn accept_follow(
|
||||||
|
follow_req: Follow,
|
||||||
|
data: &Data<StateHandle>,
|
||||||
|
) -> Result<(), crate::error::Error> {
|
||||||
|
let local_user = follow_req.actor.dereference(data).await?;
|
||||||
|
let follower = follow_req.object.dereference(data).await?;
|
||||||
|
let follow_relation = save_follow(local_user, follower.clone()).await?;
|
||||||
|
Accept::send(follow_relation, follow_req, follower.inbox().clone(), data).await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
async fn save_follow(
|
async fn save_follow(
|
||||||
local_user: user::Model,
|
local_user: user::Model,
|
||||||
follower: user::Model,
|
follower: user::Model,
|
||||||
) -> Result<(), crate::error::Error> {
|
) -> Result<follow_relation::Model, crate::error::Error> {
|
||||||
let url = Url::parse(&follower.url)?;
|
let url = Url::parse(&follower.url)?;
|
||||||
let follow_relation = follow_relation::ActiveModel {
|
let follow_relation = follow_relation::ActiveModel {
|
||||||
followee_id: Set(local_user.id.clone()),
|
followee_id: Set(local_user.id.clone()),
|
||||||
|
|
@ -58,6 +167,6 @@ async fn save_follow(
|
||||||
follower_inbox: Set(Some(follower.inbox.clone())),
|
follower_inbox: Set(Some(follower.inbox.clone())),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
follow_relation.insert(DB.get().unwrap()).await?;
|
let model = follow_relation.insert(DB.get().unwrap()).await?;
|
||||||
Ok(())
|
Ok(model)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
28
src/main.rs
28
src/main.rs
|
|
@ -28,13 +28,13 @@ use tokio::signal;
|
||||||
use tracing::{info, instrument::WithSubscriber};
|
use tracing::{info, instrument::WithSubscriber};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
use crate::entities::user;
|
|
||||||
use crate::utils::generate_object_id;
|
use crate::utils::generate_object_id;
|
||||||
use crate::{
|
use crate::{
|
||||||
activities::create_post::CreatePost,
|
activities::create_post::CreatePost,
|
||||||
database::{Config, State},
|
database::{Config, State},
|
||||||
objects::post::{Mention, Note},
|
objects::post::{Mention, Note},
|
||||||
};
|
};
|
||||||
|
use crate::{activities::follow::Follow, entities::user};
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
|
|
||||||
mod activities;
|
mod activities;
|
||||||
|
|
@ -105,6 +105,31 @@ async fn post_manually(
|
||||||
Ok(HttpResponse::Ok().json(Response { health: true }))
|
Ok(HttpResponse::Ok().json(Response { health: true }))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[get("/test/follow/{user}")]
|
||||||
|
async fn follow_manually(
|
||||||
|
path: web::Path<String>,
|
||||||
|
state: web::Data<State>,
|
||||||
|
) -> actix_web::Result<HttpResponse, error::Error> {
|
||||||
|
let local_user = state.local_user().await?;
|
||||||
|
let data = FEDERATION_CONFIG.get().unwrap();
|
||||||
|
let followee =
|
||||||
|
webfinger_resolve_actor::<State, user::Model>(path.as_str(), &data.to_request_data())
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
let followee_object: ObjectId<user::Model> = Url::parse(&followee.id)?.into();
|
||||||
|
let localuser_object: ObjectId<user::Model> = Url::parse(&local_user.id)?.into();
|
||||||
|
|
||||||
|
Follow::send(
|
||||||
|
localuser_object,
|
||||||
|
followee_object,
|
||||||
|
followee.shared_inbox_or_inbox(),
|
||||||
|
&data.to_request_data(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(HttpResponse::Ok().json(Response { health: true }))
|
||||||
|
}
|
||||||
|
|
||||||
const DOMAIN_DEF: &str = "example.com";
|
const DOMAIN_DEF: &str = "example.com";
|
||||||
const LOCAL_USER_NAME: &str = "example";
|
const LOCAL_USER_NAME: &str = "example";
|
||||||
|
|
||||||
|
|
@ -209,6 +234,7 @@ async fn main() -> actix_web::Result<(), anyhow::Error> {
|
||||||
.wrap(prometheus.clone())
|
.wrap(prometheus.clone())
|
||||||
.wrap(FederationMiddleware::new(data.clone()))
|
.wrap(FederationMiddleware::new(data.clone()))
|
||||||
.service(post_manually)
|
.service(post_manually)
|
||||||
|
.service(follow_manually)
|
||||||
.route("/{user}", web::get().to(http_get_user))
|
.route("/{user}", web::get().to(http_get_user))
|
||||||
.route("/{user}/inbox", web::post().to(http_post_user_inbox))
|
.route("/{user}/inbox", web::post().to(http_post_user_inbox))
|
||||||
.route("/.well-known/webfinger", web::get().to(webfinger))
|
.route("/.well-known/webfinger", web::get().to(webfinger))
|
||||||
|
|
|
||||||
|
|
@ -11,3 +11,8 @@ pub fn generate_object_id(domain: &str) -> Result<Url, ParseError> {
|
||||||
.collect();
|
.collect();
|
||||||
Url::parse(&format!("https://{}/objects/{}", domain, id))
|
Url::parse(&format!("https://{}/objects/{}", domain, id))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Generate a follow accept id
|
||||||
|
pub fn generate_follow_accept_id(domain: &str, db_id: i32) -> Result<Url, ParseError> {
|
||||||
|
Url::parse(&format!("https://{}/activities/follow/{}", domain, db_id))
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue