3 following::accept::AcceptFollowCommunity,
8 context::lemmy_context,
9 fetcher::object_id::ObjectId,
10 objects::{community::ApubCommunity, person::ApubPerson},
13 use activitystreams::{
14 activity::kind::FollowType,
16 primitives::OneOrMany,
19 use lemmy_api_common::blocking;
22 traits::{ActivityFields, ActivityHandler, ActorType},
23 verify::verify_urls_match,
25 use lemmy_db_schema::{
26 source::community::{CommunityFollower, CommunityFollowerForm},
29 use lemmy_utils::LemmyError;
30 use lemmy_websocket::LemmyContext;
31 use serde::{Deserialize, Serialize};
34 #[derive(Clone, Debug, Deserialize, Serialize, ActivityFields)]
35 #[serde(rename_all = "camelCase")]
36 pub struct FollowCommunity {
37 pub(in crate::activities::following) actor: ObjectId<ApubPerson>,
38 pub(in crate::activities::following) to: [ObjectId<ApubCommunity>; 1],
39 pub(in crate::activities::following) object: ObjectId<ApubCommunity>,
40 #[serde(rename = "type")]
43 #[serde(rename = "@context")]
44 context: OneOrMany<AnyBase>,
49 impl FollowCommunity {
50 pub(in crate::activities::following) fn new(
52 community: &ApubCommunity,
53 context: &LemmyContext,
54 ) -> Result<FollowCommunity, LemmyError> {
56 actor: ObjectId::new(actor.actor_id()),
57 to: [ObjectId::new(community.actor_id())],
58 object: ObjectId::new(community.actor_id()),
59 kind: FollowType::Follow,
60 id: generate_activity_id(
62 &context.settings().get_protocol_and_hostname(),
64 context: lemmy_context(),
65 unparsed: Default::default(),
70 community: &ApubCommunity,
71 context: &LemmyContext,
72 ) -> Result<(), LemmyError> {
73 let community_follower_form = CommunityFollowerForm {
74 community_id: community.id,
78 blocking(context.pool(), move |conn| {
79 CommunityFollower::follow(conn, &community_follower_form).ok()
83 let follow = FollowCommunity::new(actor, community, context)?;
84 let inbox = vec![community.inbox_url.clone().into()];
85 send_lemmy_activity(context, &follow, &follow.id, actor, inbox, true).await
89 #[async_trait::async_trait(?Send)]
90 impl ActivityHandler for FollowCommunity {
91 type DataType = LemmyContext;
94 context: &Data<LemmyContext>,
95 request_counter: &mut i32,
96 ) -> Result<(), LemmyError> {
97 verify_activity(self, &context.settings())?;
98 verify_urls_match(self.to[0].inner(), self.object.inner())?;
99 verify_person(&self.actor, context, request_counter).await?;
105 context: &Data<LemmyContext>,
106 request_counter: &mut i32,
107 ) -> Result<(), LemmyError> {
108 let actor = self.actor.dereference(context, request_counter).await?;
109 let community = self.to[0].dereference(context, request_counter).await?;
110 let community_follower_form = CommunityFollowerForm {
111 community_id: community.id,
116 // This will fail if they're already a follower, but ignore the error.
117 blocking(context.pool(), move |conn| {
118 CommunityFollower::follow(conn, &community_follower_form).ok()
122 AcceptFollowCommunity::send(self, context, request_counter).await