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