]> Untitled Git - lemmy.git/blob - crates/apub/src/activities/voting/vote.rs
0f5a2b5c40231d1222f304e69e91b6cd505c0cc3
[lemmy.git] / crates / apub / src / activities / voting / vote.rs
1 use crate::{
2   activities::{
3     community::announce::AnnouncableActivities,
4     generate_activity_id,
5     verify_activity,
6     verify_person_in_community,
7     voting::{vote_comment, vote_post},
8   },
9   activity_queue::send_to_community_new,
10   extensions::context::lemmy_context,
11   fetcher::{
12     objects::get_or_fetch_and_insert_post_or_comment,
13     person::get_or_fetch_and_upsert_person,
14   },
15   ActorType,
16   PostOrComment,
17 };
18 use anyhow::anyhow;
19 use lemmy_api_common::blocking;
20 use lemmy_apub_lib::{values::PublicUrl, ActivityCommonFields, ActivityHandler};
21 use lemmy_db_queries::Crud;
22 use lemmy_db_schema::{
23   source::{community::Community, person::Person},
24   CommunityId,
25 };
26 use lemmy_utils::LemmyError;
27 use lemmy_websocket::LemmyContext;
28 use serde::{Deserialize, Serialize};
29 use std::{convert::TryFrom, ops::Deref};
30 use strum_macros::ToString;
31 use url::Url;
32
33 #[derive(Clone, Debug, ToString, Deserialize, Serialize)]
34 pub enum VoteType {
35   Like,
36   Dislike,
37 }
38
39 impl TryFrom<i16> for VoteType {
40   type Error = LemmyError;
41
42   fn try_from(value: i16) -> Result<Self, Self::Error> {
43     match value {
44       1 => Ok(VoteType::Like),
45       -1 => Ok(VoteType::Dislike),
46       _ => Err(anyhow!("invalid vote value").into()),
47     }
48   }
49 }
50
51 impl From<&VoteType> for i16 {
52   fn from(value: &VoteType) -> i16 {
53     match value {
54       VoteType::Like => 1,
55       VoteType::Dislike => -1,
56     }
57   }
58 }
59
60 #[derive(Clone, Debug, Deserialize, Serialize)]
61 #[serde(rename_all = "camelCase")]
62 pub struct Vote {
63   pub(in crate::activities::voting) to: PublicUrl,
64   pub(in crate::activities::voting) object: Url,
65   pub(in crate::activities::voting) cc: [Url; 1],
66   #[serde(rename = "type")]
67   pub(in crate::activities::voting) kind: VoteType,
68   #[serde(flatten)]
69   pub(in crate::activities::voting) common: ActivityCommonFields,
70 }
71
72 impl Vote {
73   pub async fn send(
74     object: &PostOrComment,
75     actor: &Person,
76     community_id: CommunityId,
77     kind: VoteType,
78     context: &LemmyContext,
79   ) -> Result<(), LemmyError> {
80     let community = blocking(context.pool(), move |conn| {
81       Community::read(conn, community_id)
82     })
83     .await??;
84     let id = generate_activity_id(kind.clone())?;
85
86     let vote = Vote {
87       to: PublicUrl::Public,
88       object: object.ap_id(),
89       cc: [community.actor_id()],
90       kind,
91       common: ActivityCommonFields {
92         context: lemmy_context(),
93         id: id.clone(),
94         actor: actor.actor_id(),
95         unparsed: Default::default(),
96       },
97     };
98     let activity = AnnouncableActivities::Vote(vote);
99     send_to_community_new(activity, &id, actor, &community, vec![], context).await
100   }
101 }
102
103 #[async_trait::async_trait(?Send)]
104 impl ActivityHandler for Vote {
105   async fn verify(
106     &self,
107     context: &LemmyContext,
108     request_counter: &mut i32,
109   ) -> Result<(), LemmyError> {
110     verify_activity(self.common())?;
111     verify_person_in_community(&self.common.actor, &self.cc[0], context, request_counter).await?;
112     Ok(())
113   }
114
115   async fn receive(
116     &self,
117     context: &LemmyContext,
118     request_counter: &mut i32,
119   ) -> Result<(), LemmyError> {
120     let actor =
121       get_or_fetch_and_upsert_person(&self.common.actor, context, request_counter).await?;
122     let object =
123       get_or_fetch_and_insert_post_or_comment(&self.object, context, request_counter).await?;
124     match object {
125       PostOrComment::Post(p) => vote_post(&self.kind, actor, p.deref(), context).await,
126       PostOrComment::Comment(c) => vote_comment(&self.kind, actor, c.deref(), context).await,
127     }
128   }
129
130   fn common(&self) -> &ActivityCommonFields {
131     &self.common
132   }
133 }