3 following::accept::AcceptFollowCommunity,
8 context::lemmy_context,
9 fetcher::object_id::ObjectId,
12 use activitystreams::{
13 activity::kind::FollowType,
15 primitives::OneOrMany,
18 use lemmy_api_common::blocking;
21 traits::{ActivityFields, ActivityHandler, ActorType},
22 verify::verify_urls_match,
24 use lemmy_db_queries::Followable;
25 use lemmy_db_schema::source::{
26 community::{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<Person>,
38 // TODO: is there any reason to put the same community id twice, in to and object?
39 pub(in crate::activities::following) to: ObjectId<Community>,
40 pub(in crate::activities::following) object: ObjectId<Community>,
41 #[serde(rename = "type")]
44 #[serde(rename = "@context")]
45 context: OneOrMany<AnyBase>,
50 impl FollowCommunity {
51 pub(in crate::activities::following) fn new(
53 community: &Community,
54 context: &LemmyContext,
55 ) -> Result<FollowCommunity, LemmyError> {
57 actor: ObjectId::new(actor.actor_id()),
58 to: ObjectId::new(community.actor_id()),
59 object: ObjectId::new(community.actor_id()),
60 kind: FollowType::Follow,
61 id: generate_activity_id(
63 &context.settings().get_protocol_and_hostname(),
65 context: lemmy_context(),
66 unparsed: Default::default(),
71 community: &Community,
72 context: &LemmyContext,
73 ) -> Result<(), LemmyError> {
74 let community_follower_form = CommunityFollowerForm {
75 community_id: community.id,
79 blocking(context.pool(), move |conn| {
80 CommunityFollower::follow(conn, &community_follower_form).ok()
84 let follow = FollowCommunity::new(actor, community, context)?;
85 let inbox = vec![community.inbox_url.clone().into()];
86 send_lemmy_activity(context, &follow, &follow.id, actor, inbox, true).await
90 #[async_trait::async_trait(?Send)]
91 impl ActivityHandler for FollowCommunity {
92 type DataType = LemmyContext;
95 context: &Data<LemmyContext>,
96 request_counter: &mut i32,
97 ) -> Result<(), LemmyError> {
98 verify_activity(self, &context.settings())?;
99 verify_urls_match(self.to.inner(), self.object.inner())?;
100 verify_person(&self.actor, context, request_counter).await?;
106 context: &Data<LemmyContext>,
107 request_counter: &mut i32,
108 ) -> Result<(), LemmyError> {
109 let actor = self.actor.dereference(context, request_counter).await?;
110 let community = self.object.dereference(context, request_counter).await?;
111 let community_follower_form = CommunityFollowerForm {
112 community_id: community.id,
117 // This will fail if they're already a follower, but ignore the error.
118 blocking(context.pool(), move |conn| {
119 CommunityFollower::follow(conn, &community_follower_form).ok()
123 AcceptFollowCommunity::send(self, context, request_counter).await