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