3 following::accept::AcceptFollowCommunity,
8 activity_queue::send_activity_new,
9 extensions::context::lemmy_context,
10 fetcher::object_id::ObjectId,
13 use activitystreams::{
14 activity::kind::FollowType,
16 primitives::OneOrMany,
19 use lemmy_api_common::blocking;
20 use lemmy_apub_lib::{verify_urls_match, ActivityFields, ActivityHandler};
21 use lemmy_db_queries::Followable;
22 use lemmy_db_schema::source::{
23 community::{Community, CommunityFollower, CommunityFollowerForm},
26 use lemmy_utils::LemmyError;
27 use lemmy_websocket::LemmyContext;
28 use serde::{Deserialize, Serialize};
31 #[derive(Clone, Debug, Deserialize, Serialize, ActivityFields)]
32 #[serde(rename_all = "camelCase")]
33 pub struct FollowCommunity {
34 actor: ObjectId<Person>,
35 // TODO: is there any reason to put the same community id twice, in to and object?
36 pub(in crate::activities::following) to: ObjectId<Community>,
37 pub(in crate::activities::following) object: ObjectId<Community>,
38 #[serde(rename = "type")]
41 #[serde(rename = "@context")]
42 context: OneOrMany<AnyBase>,
47 impl FollowCommunity {
48 pub(in crate::activities::following) fn new(
50 community: &Community,
51 context: &LemmyContext,
52 ) -> Result<FollowCommunity, LemmyError> {
54 actor: ObjectId::new(actor.actor_id()),
55 to: ObjectId::new(community.actor_id()),
56 object: ObjectId::new(community.actor_id()),
57 kind: FollowType::Follow,
58 id: generate_activity_id(
60 &context.settings().get_protocol_and_hostname(),
62 context: lemmy_context(),
63 unparsed: Default::default(),
68 community: &Community,
69 context: &LemmyContext,
70 ) -> Result<(), LemmyError> {
71 let community_follower_form = CommunityFollowerForm {
72 community_id: community.id,
76 blocking(context.pool(), move |conn| {
77 CommunityFollower::follow(conn, &community_follower_form).ok()
81 let follow = FollowCommunity::new(actor, community, context)?;
82 let inbox = vec![community.inbox_url.clone().into()];
83 send_activity_new(context, &follow, &follow.id, actor, inbox, true).await
87 #[async_trait::async_trait(?Send)]
88 impl ActivityHandler for FollowCommunity {
91 context: &LemmyContext,
92 request_counter: &mut i32,
93 ) -> Result<(), LemmyError> {
94 verify_activity(self, &context.settings())?;
95 verify_urls_match(self.to.inner(), self.object.inner())?;
96 verify_person(&self.actor, context, request_counter).await?;
102 context: &LemmyContext,
103 request_counter: &mut i32,
104 ) -> Result<(), LemmyError> {
105 let actor = self.actor.dereference(context, request_counter).await?;
106 let community = self.object.dereference(context, request_counter).await?;
107 let community_follower_form = CommunityFollowerForm {
108 community_id: community.id,
113 // This will fail if they're already a follower, but ignore the error.
114 blocking(context.pool(), move |conn| {
115 CommunityFollower::follow(conn, &community_follower_form).ok()
119 AcceptFollowCommunity::send(self, context).await