]> Untitled Git - lemmy.git/blob - crates/db_queries/src/source/activity.rs
964e50424e221cd46b9f174d6c7eaf403fc426cd
[lemmy.git] / crates / db_queries / src / source / activity.rs
1 use crate::Crud;
2 use diesel::{dsl::*, result::Error, sql_types::Text, *};
3 use lemmy_db_schema::{source::activity::*, Url};
4 use log::debug;
5 use serde::Serialize;
6 use serde_json::Value;
7 use std::{
8   fmt::Debug,
9   io::{Error as IoError, ErrorKind},
10 };
11
12 impl Crud<ActivityForm> for Activity {
13   fn read(conn: &PgConnection, activity_id: i32) -> Result<Self, Error> {
14     use lemmy_db_schema::schema::activity::dsl::*;
15     activity.find(activity_id).first::<Self>(conn)
16   }
17
18   fn create(conn: &PgConnection, new_activity: &ActivityForm) -> Result<Self, Error> {
19     use lemmy_db_schema::schema::activity::dsl::*;
20     insert_into(activity)
21       .values(new_activity)
22       .get_result::<Self>(conn)
23   }
24
25   fn update(
26     conn: &PgConnection,
27     activity_id: i32,
28     new_activity: &ActivityForm,
29   ) -> Result<Self, Error> {
30     use lemmy_db_schema::schema::activity::dsl::*;
31     diesel::update(activity.find(activity_id))
32       .set(new_activity)
33       .get_result::<Self>(conn)
34   }
35   fn delete(conn: &PgConnection, activity_id: i32) -> Result<usize, Error> {
36     use lemmy_db_schema::schema::activity::dsl::*;
37     diesel::delete(activity.find(activity_id)).execute(conn)
38   }
39 }
40
41 pub trait Activity_ {
42   fn insert<T>(
43     conn: &PgConnection,
44     ap_id: String,
45     data: &T,
46     local: bool,
47     sensitive: bool,
48   ) -> Result<Activity, IoError>
49   where
50     T: Serialize + Debug;
51
52   fn read_from_apub_id(conn: &PgConnection, object_id: &str) -> Result<Activity, Error>;
53
54   /// Returns up to 20 activities of type `Announce/Create/Page` from the community
55   fn read_community_outbox(
56     conn: &PgConnection,
57     community_actor_id: &Url,
58   ) -> Result<Vec<Value>, Error>;
59 }
60
61 impl Activity_ for Activity {
62   fn insert<T>(
63     conn: &PgConnection,
64     ap_id: String,
65     data: &T,
66     local: bool,
67     sensitive: bool,
68   ) -> Result<Activity, IoError>
69   where
70     T: Serialize + Debug,
71   {
72     debug!("{}", serde_json::to_string_pretty(&data)?);
73     let activity_form = ActivityForm {
74       ap_id,
75       data: serde_json::to_value(&data)?,
76       local,
77       sensitive,
78       updated: None,
79     };
80     let result = Activity::create(&conn, &activity_form);
81     match result {
82       Ok(s) => Ok(s),
83       Err(e) => Err(IoError::new(
84         ErrorKind::Other,
85         format!("Failed to insert activity into database: {}", e),
86       )),
87     }
88   }
89
90   fn read_from_apub_id(conn: &PgConnection, object_id: &str) -> Result<Activity, Error> {
91     use lemmy_db_schema::schema::activity::dsl::*;
92     activity.filter(ap_id.eq(object_id)).first::<Self>(conn)
93   }
94
95   fn read_community_outbox(
96     conn: &PgConnection,
97     community_actor_id: &Url,
98   ) -> Result<Vec<Value>, Error> {
99     use lemmy_db_schema::schema::activity::dsl::*;
100     let res: Vec<Value> = activity
101       .select(data)
102       .filter(
103         sql("activity.data ->> 'type' = 'Announce'")
104           .sql(" AND activity.data -> 'object' ->> 'type' = 'Create'")
105           .sql(" AND activity.data -> 'object' -> 'object' ->> 'type' = 'Page'")
106           .sql(" AND activity.data ->> 'actor' = ")
107           .bind::<Text, _>(community_actor_id),
108       )
109       .limit(20)
110       .get_results(conn)?;
111     Ok(res)
112   }
113 }
114
115 #[cfg(test)]
116 mod tests {
117   use crate::{
118     establish_unpooled_connection,
119     source::activity::Activity_,
120     Crud,
121     ListingType,
122     SortType,
123   };
124   use lemmy_db_schema::source::{
125     activity::{Activity, ActivityForm},
126     user::{UserForm, User_},
127   };
128   use serde_json::Value;
129
130   #[test]
131   fn test_crud() {
132     let conn = establish_unpooled_connection();
133
134     let creator_form = UserForm {
135       name: "activity_creator_pm".into(),
136       preferred_username: None,
137       password_encrypted: "nope".into(),
138       email: None,
139       matrix_user_id: None,
140       avatar: None,
141       banner: None,
142       admin: false,
143       banned: Some(false),
144       published: None,
145       updated: None,
146       show_nsfw: false,
147       theme: "browser".into(),
148       default_sort_type: SortType::Hot as i16,
149       default_listing_type: ListingType::Subscribed as i16,
150       lang: "browser".into(),
151       show_avatars: true,
152       send_notifications_to_email: false,
153       actor_id: None,
154       bio: None,
155       local: true,
156       private_key: None,
157       public_key: None,
158       last_refreshed_at: None,
159     };
160
161     let inserted_creator = User_::create(&conn, &creator_form).unwrap();
162
163     let ap_id =
164       "https://enterprise.lemmy.ml/activities/delete/f1b5d57c-80f8-4e03-a615-688d552e946c";
165     let test_json: Value = serde_json::from_str(
166       r#"{
167     "@context": "https://www.w3.org/ns/activitystreams",
168     "id": "https://enterprise.lemmy.ml/activities/delete/f1b5d57c-80f8-4e03-a615-688d552e946c",
169     "type": "Delete",
170     "actor": "https://enterprise.lemmy.ml/u/riker",
171     "to": "https://www.w3.org/ns/activitystreams#Public",
172     "cc": [
173         "https://enterprise.lemmy.ml/c/main/"
174     ],
175     "object": "https://enterprise.lemmy.ml/post/32"
176     }"#,
177     )
178     .unwrap();
179     let activity_form = ActivityForm {
180       ap_id: ap_id.to_string(),
181       data: test_json.to_owned(),
182       local: true,
183       sensitive: false,
184       updated: None,
185     };
186
187     let inserted_activity = Activity::create(&conn, &activity_form).unwrap();
188
189     let expected_activity = Activity {
190       ap_id: Some(ap_id.to_string()),
191       id: inserted_activity.id,
192       data: test_json,
193       local: true,
194       sensitive: Some(false),
195       published: inserted_activity.published,
196       updated: None,
197     };
198
199     let read_activity = Activity::read(&conn, inserted_activity.id).unwrap();
200     let read_activity_by_apub_id = Activity::read_from_apub_id(&conn, ap_id).unwrap();
201     User_::delete(&conn, inserted_creator.id).unwrap();
202     Activity::delete(&conn, inserted_activity.id).unwrap();
203
204     assert_eq!(expected_activity, read_activity);
205     assert_eq!(expected_activity, read_activity_by_apub_id);
206     assert_eq!(expected_activity, inserted_activity);
207   }
208 }