]> Untitled Git - lemmy.git/blob - crates/apub/src/activities/voting/vote.rs
Fix clippy warnings added in nightly (#1833)
[lemmy.git] / crates / apub / src / activities / voting / vote.rs
1 use crate::{
2   activities::{
3     community::{announce::AnnouncableActivities, send_to_community},
4     generate_activity_id,
5     verify_activity,
6     verify_person_in_community,
7     voting::{vote_comment, vote_post},
8   },
9   context::lemmy_context,
10   fetcher::object_id::ObjectId,
11   PostOrComment,
12 };
13 use activitystreams::{base::AnyBase, primitives::OneOrMany, unparsed::Unparsed};
14 use anyhow::anyhow;
15 use lemmy_api_common::blocking;
16 use lemmy_apub_lib::{
17   data::Data,
18   traits::{ActivityFields, ActivityHandler, ActorType},
19   values::PublicUrl,
20 };
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, ActivityFields)]
61 #[serde(rename_all = "camelCase")]
62 pub struct Vote {
63   actor: ObjectId<Person>,
64   to: [PublicUrl; 1],
65   pub(in crate::activities::voting) object: ObjectId<PostOrComment>,
66   cc: [ObjectId<Community>; 1],
67   #[serde(rename = "type")]
68   pub(in crate::activities::voting) kind: VoteType,
69   id: Url,
70   #[serde(rename = "@context")]
71   context: OneOrMany<AnyBase>,
72   #[serde(flatten)]
73   unparsed: Unparsed,
74 }
75
76 impl Vote {
77   pub(in crate::activities::voting) fn new(
78     object: &PostOrComment,
79     actor: &Person,
80     community: &Community,
81     kind: VoteType,
82     context: &LemmyContext,
83   ) -> Result<Vote, LemmyError> {
84     Ok(Vote {
85       actor: ObjectId::new(actor.actor_id()),
86       to: [PublicUrl::Public],
87       object: ObjectId::new(object.ap_id()),
88       cc: [ObjectId::new(community.actor_id())],
89       kind: kind.clone(),
90       id: generate_activity_id(kind, &context.settings().get_protocol_and_hostname())?,
91       context: lemmy_context(),
92       unparsed: Default::default(),
93     })
94   }
95
96   pub async fn send(
97     object: &PostOrComment,
98     actor: &Person,
99     community_id: CommunityId,
100     kind: VoteType,
101     context: &LemmyContext,
102   ) -> Result<(), LemmyError> {
103     let community = blocking(context.pool(), move |conn| {
104       Community::read(conn, community_id)
105     })
106     .await??;
107     let vote = Vote::new(object, actor, &community, kind, context)?;
108     let vote_id = vote.id.clone();
109
110     let activity = AnnouncableActivities::Vote(vote);
111     send_to_community(activity, &vote_id, actor, &community, vec![], context).await
112   }
113 }
114
115 #[async_trait::async_trait(?Send)]
116 impl ActivityHandler for Vote {
117   type DataType = LemmyContext;
118   async fn verify(
119     &self,
120     context: &Data<LemmyContext>,
121     request_counter: &mut i32,
122   ) -> Result<(), LemmyError> {
123     verify_activity(self, &context.settings())?;
124     verify_person_in_community(&self.actor, &self.cc[0], context, request_counter).await?;
125     Ok(())
126   }
127
128   async fn receive(
129     self,
130     context: &Data<LemmyContext>,
131     request_counter: &mut i32,
132   ) -> Result<(), LemmyError> {
133     let actor = self.actor.dereference(context, request_counter).await?;
134     let object = self.object.dereference(context, request_counter).await?;
135     match object {
136       PostOrComment::Post(p) => vote_post(&self.kind, actor, p.deref(), context).await,
137       PostOrComment::Comment(c) => vote_comment(&self.kind, actor, &c, context).await,
138     }
139   }
140 }