]> Untitled Git - lemmy.git/blob - crates/apub/src/activities/voting/mod.rs
Make functions work with both connection and pool (#3420)
[lemmy.git] / crates / apub / src / activities / voting / mod.rs
1 use crate::{
2   activities::community::send_activity_in_community,
3   activity_lists::AnnouncableActivities,
4   fetcher::post_or_comment::PostOrComment,
5   objects::{comment::ApubComment, person::ApubPerson, post::ApubPost},
6   protocol::activities::voting::{
7     undo_vote::UndoVote,
8     vote::{Vote, VoteType},
9   },
10   SendActivity,
11 };
12 use activitypub_federation::{config::Data, fetch::object_id::ObjectId};
13 use lemmy_api_common::{
14   comment::{CommentResponse, CreateCommentLike},
15   context::LemmyContext,
16   post::{CreatePostLike, PostResponse},
17   sensitive::Sensitive,
18   utils::local_user_view_from_jwt,
19 };
20 use lemmy_db_schema::{
21   newtypes::CommunityId,
22   source::{
23     comment::{CommentLike, CommentLikeForm},
24     community::Community,
25     person::Person,
26     post::{PostLike, PostLikeForm},
27   },
28   traits::{Crud, Likeable},
29 };
30 use lemmy_utils::error::LemmyError;
31
32 pub mod undo_vote;
33 pub mod vote;
34
35 #[async_trait::async_trait]
36 impl SendActivity for CreatePostLike {
37   type Response = PostResponse;
38
39   async fn send_activity(
40     request: &Self,
41     response: &Self::Response,
42     context: &Data<LemmyContext>,
43   ) -> Result<(), LemmyError> {
44     let object_id = ObjectId::from(response.post_view.post.ap_id.clone());
45     let community_id = response.post_view.community.id;
46     send_activity(
47       object_id,
48       community_id,
49       request.score,
50       &request.auth,
51       context,
52     )
53     .await
54   }
55 }
56
57 #[async_trait::async_trait]
58 impl SendActivity for CreateCommentLike {
59   type Response = CommentResponse;
60
61   async fn send_activity(
62     request: &Self,
63     response: &Self::Response,
64     context: &Data<LemmyContext>,
65   ) -> Result<(), LemmyError> {
66     let object_id = ObjectId::from(response.comment_view.comment.ap_id.clone());
67     let community_id = response.comment_view.community.id;
68     send_activity(
69       object_id,
70       community_id,
71       request.score,
72       &request.auth,
73       context,
74     )
75     .await
76   }
77 }
78
79 async fn send_activity(
80   object_id: ObjectId<PostOrComment>,
81   community_id: CommunityId,
82   score: i16,
83   jwt: &Sensitive<String>,
84   context: &Data<LemmyContext>,
85 ) -> Result<(), LemmyError> {
86   let community = Community::read(&mut context.pool(), community_id)
87     .await?
88     .into();
89   let local_user_view = local_user_view_from_jwt(jwt, context).await?;
90   let actor = Person::read(&mut context.pool(), local_user_view.person.id)
91     .await?
92     .into();
93
94   // score of 1 means upvote, -1 downvote, 0 undo a previous vote
95   if score != 0 {
96     let vote = Vote::new(object_id, &actor, &community, score.try_into()?, context)?;
97     let activity = AnnouncableActivities::Vote(vote);
98     send_activity_in_community(activity, &actor, &community, vec![], false, context).await
99   } else {
100     // Lemmy API doesnt distinguish between Undo/Like and Undo/Dislike, so we hardcode it here.
101     let vote = Vote::new(object_id, &actor, &community, VoteType::Like, context)?;
102     let undo_vote = UndoVote::new(vote, &actor, &community, context)?;
103     let activity = AnnouncableActivities::UndoVote(undo_vote);
104     send_activity_in_community(activity, &actor, &community, vec![], false, context).await
105   }
106 }
107
108 #[tracing::instrument(skip_all)]
109 async fn vote_comment(
110   vote_type: &VoteType,
111   actor: ApubPerson,
112   comment: &ApubComment,
113   context: &Data<LemmyContext>,
114 ) -> Result<(), LemmyError> {
115   let comment_id = comment.id;
116   let like_form = CommentLikeForm {
117     comment_id,
118     post_id: comment.post_id,
119     person_id: actor.id,
120     score: vote_type.into(),
121   };
122   let person_id = actor.id;
123   CommentLike::remove(&mut context.pool(), person_id, comment_id).await?;
124   CommentLike::like(&mut context.pool(), &like_form).await?;
125   Ok(())
126 }
127
128 #[tracing::instrument(skip_all)]
129 async fn vote_post(
130   vote_type: &VoteType,
131   actor: ApubPerson,
132   post: &ApubPost,
133   context: &Data<LemmyContext>,
134 ) -> Result<(), LemmyError> {
135   let post_id = post.id;
136   let like_form = PostLikeForm {
137     post_id: post.id,
138     person_id: actor.id,
139     score: vote_type.into(),
140   };
141   let person_id = actor.id;
142   PostLike::remove(&mut context.pool(), person_id, post_id).await?;
143   PostLike::like(&mut context.pool(), &like_form).await?;
144   Ok(())
145 }
146
147 #[tracing::instrument(skip_all)]
148 async fn undo_vote_comment(
149   actor: ApubPerson,
150   comment: &ApubComment,
151   context: &Data<LemmyContext>,
152 ) -> Result<(), LemmyError> {
153   let comment_id = comment.id;
154   let person_id = actor.id;
155   CommentLike::remove(&mut context.pool(), person_id, comment_id).await?;
156   Ok(())
157 }
158
159 #[tracing::instrument(skip_all)]
160 async fn undo_vote_post(
161   actor: ApubPerson,
162   post: &ApubPost,
163   context: &Data<LemmyContext>,
164 ) -> Result<(), LemmyError> {
165   let post_id = post.id;
166   let person_id = actor.id;
167   PostLike::remove(&mut context.pool(), person_id, post_id).await?;
168   Ok(())
169 }