]> Untitled Git - lemmy.git/blob - crates/db_schema/src/impls/person.rs
Merge crates db_schema and db_queries
[lemmy.git] / crates / db_schema / src / impls / person.rs
1 use crate::{
2   naive_now,
3   newtypes::{DbUrl, PersonId},
4   schema::person::dsl::*,
5   source::person::{Person, PersonForm},
6   traits::Crud,
7 };
8 use chrono::NaiveDateTime;
9 use diesel::{dsl::*, result::Error, ExpressionMethods, PgConnection, QueryDsl, RunQueryDsl, *};
10 use lemmy_apub_lib::traits::{ActorType, ApubObject};
11 use lemmy_utils::LemmyError;
12 use url::Url;
13
14 mod safe_type {
15   use crate::{schema::person::columns::*, source::person::Person, traits::ToSafe};
16
17   type Columns = (
18     id,
19     name,
20     display_name,
21     avatar,
22     banned,
23     published,
24     updated,
25     actor_id,
26     bio,
27     local,
28     banner,
29     deleted,
30     inbox_url,
31     shared_inbox_url,
32     matrix_user_id,
33     admin,
34     bot_account,
35   );
36
37   impl ToSafe for Person {
38     type SafeColumns = Columns;
39     fn safe_columns_tuple() -> Self::SafeColumns {
40       (
41         id,
42         name,
43         display_name,
44         avatar,
45         banned,
46         published,
47         updated,
48         actor_id,
49         bio,
50         local,
51         banner,
52         deleted,
53         inbox_url,
54         shared_inbox_url,
55         matrix_user_id,
56         admin,
57         bot_account,
58       )
59     }
60   }
61 }
62
63 mod safe_type_alias_1 {
64   use crate::{schema::person_alias_1::columns::*, source::person::PersonAlias1, traits::ToSafe};
65
66   type Columns = (
67     id,
68     name,
69     display_name,
70     avatar,
71     banned,
72     published,
73     updated,
74     actor_id,
75     bio,
76     local,
77     banner,
78     deleted,
79     inbox_url,
80     shared_inbox_url,
81     matrix_user_id,
82     admin,
83     bot_account,
84   );
85
86   impl ToSafe for PersonAlias1 {
87     type SafeColumns = Columns;
88     fn safe_columns_tuple() -> Self::SafeColumns {
89       (
90         id,
91         name,
92         display_name,
93         avatar,
94         banned,
95         published,
96         updated,
97         actor_id,
98         bio,
99         local,
100         banner,
101         deleted,
102         inbox_url,
103         shared_inbox_url,
104         matrix_user_id,
105         admin,
106         bot_account,
107       )
108     }
109   }
110 }
111
112 mod safe_type_alias_2 {
113   use crate::{schema::person_alias_2::columns::*, source::person::PersonAlias2, traits::ToSafe};
114
115   type Columns = (
116     id,
117     name,
118     display_name,
119     avatar,
120     banned,
121     published,
122     updated,
123     actor_id,
124     bio,
125     local,
126     banner,
127     deleted,
128     inbox_url,
129     shared_inbox_url,
130     matrix_user_id,
131     admin,
132     bot_account,
133   );
134
135   impl ToSafe for PersonAlias2 {
136     type SafeColumns = Columns;
137     fn safe_columns_tuple() -> Self::SafeColumns {
138       (
139         id,
140         name,
141         display_name,
142         avatar,
143         banned,
144         published,
145         updated,
146         actor_id,
147         bio,
148         local,
149         banner,
150         deleted,
151         inbox_url,
152         shared_inbox_url,
153         matrix_user_id,
154         admin,
155         bot_account,
156       )
157     }
158   }
159 }
160
161 impl Crud for Person {
162   type Form = PersonForm;
163   type IdType = PersonId;
164   fn read(conn: &PgConnection, person_id: PersonId) -> Result<Self, Error> {
165     person
166       .filter(deleted.eq(false))
167       .find(person_id)
168       .first::<Self>(conn)
169   }
170   fn delete(conn: &PgConnection, person_id: PersonId) -> Result<usize, Error> {
171     diesel::delete(person.find(person_id)).execute(conn)
172   }
173   fn create(conn: &PgConnection, form: &PersonForm) -> Result<Self, Error> {
174     insert_into(person).values(form).get_result::<Self>(conn)
175   }
176   fn update(conn: &PgConnection, person_id: PersonId, form: &PersonForm) -> Result<Self, Error> {
177     diesel::update(person.find(person_id))
178       .set(form)
179       .get_result::<Self>(conn)
180   }
181 }
182
183 impl Person {
184   pub fn ban_person(conn: &PgConnection, person_id: PersonId, ban: bool) -> Result<Self, Error> {
185     diesel::update(person.find(person_id))
186       .set(banned.eq(ban))
187       .get_result::<Self>(conn)
188   }
189
190   pub fn add_admin(conn: &PgConnection, person_id: PersonId, added: bool) -> Result<Self, Error> {
191     diesel::update(person.find(person_id))
192       .set(admin.eq(added))
193       .get_result::<Self>(conn)
194   }
195
196   pub fn find_by_name(conn: &PgConnection, from_name: &str) -> Result<Person, Error> {
197     person
198       .filter(deleted.eq(false))
199       .filter(local.eq(true))
200       .filter(name.ilike(from_name))
201       .first::<Person>(conn)
202   }
203
204   pub fn mark_as_updated(conn: &PgConnection, person_id: PersonId) -> Result<Person, Error> {
205     diesel::update(person.find(person_id))
206       .set((last_refreshed_at.eq(naive_now()),))
207       .get_result::<Self>(conn)
208   }
209
210   pub fn delete_account(conn: &PgConnection, person_id: PersonId) -> Result<Person, Error> {
211     use crate::schema::local_user;
212
213     // Set the local user info to none
214     diesel::update(local_user::table.filter(local_user::person_id.eq(person_id)))
215       .set((
216         local_user::email.eq::<Option<String>>(None),
217         local_user::validator_time.eq(naive_now()),
218       ))
219       .execute(conn)?;
220
221     diesel::update(person.find(person_id))
222       .set((
223         display_name.eq::<Option<String>>(None),
224         bio.eq::<Option<String>>(None),
225         matrix_user_id.eq::<Option<String>>(None),
226         deleted.eq(true),
227         updated.eq(naive_now()),
228       ))
229       .get_result::<Self>(conn)
230   }
231
232   pub fn upsert(conn: &PgConnection, person_form: &PersonForm) -> Result<Person, Error> {
233     insert_into(person)
234       .values(person_form)
235       .on_conflict(actor_id)
236       .do_update()
237       .set(person_form)
238       .get_result::<Self>(conn)
239   }
240 }
241
242 impl ApubObject for Person {
243   type DataType = PgConnection;
244
245   fn last_refreshed_at(&self) -> Option<NaiveDateTime> {
246     Some(self.last_refreshed_at)
247   }
248
249   fn read_from_apub_id(conn: &PgConnection, object_id: Url) -> Result<Option<Self>, LemmyError> {
250     use crate::schema::person::dsl::*;
251     let object_id: DbUrl = object_id.into();
252     Ok(
253       person
254         .filter(deleted.eq(false))
255         .filter(actor_id.eq(object_id))
256         .first::<Self>(conn)
257         .ok(),
258     )
259   }
260
261   fn delete(self, conn: &PgConnection) -> Result<(), LemmyError> {
262     use crate::schema::person::dsl::*;
263     diesel::update(person.find(self.id))
264       .set((deleted.eq(true), updated.eq(naive_now())))
265       .get_result::<Self>(conn)?;
266     Ok(())
267   }
268 }
269
270 impl ActorType for Person {
271   fn is_local(&self) -> bool {
272     self.local
273   }
274   fn actor_id(&self) -> Url {
275     self.actor_id.to_owned().into_inner()
276   }
277   fn name(&self) -> String {
278     self.name.clone()
279   }
280
281   fn public_key(&self) -> Option<String> {
282     self.public_key.to_owned()
283   }
284
285   fn private_key(&self) -> Option<String> {
286     self.private_key.to_owned()
287   }
288
289   fn inbox_url(&self) -> Url {
290     self.inbox_url.clone().into()
291   }
292
293   fn shared_inbox_url(&self) -> Option<Url> {
294     self.shared_inbox_url.clone().map(|s| s.into_inner())
295   }
296 }
297
298 #[cfg(test)]
299 mod tests {
300   use crate::{establish_unpooled_connection, source::person::*, traits::Crud};
301
302   #[test]
303   fn test_crud() {
304     let conn = establish_unpooled_connection();
305
306     let new_person = PersonForm {
307       name: "holly".into(),
308       ..PersonForm::default()
309     };
310
311     let inserted_person = Person::create(&conn, &new_person).unwrap();
312
313     let expected_person = Person {
314       id: inserted_person.id,
315       name: "holly".into(),
316       display_name: None,
317       avatar: None,
318       banner: None,
319       banned: false,
320       deleted: false,
321       published: inserted_person.published,
322       updated: None,
323       actor_id: inserted_person.actor_id.to_owned(),
324       bio: None,
325       local: true,
326       bot_account: false,
327       admin: false,
328       private_key: None,
329       public_key: None,
330       last_refreshed_at: inserted_person.published,
331       inbox_url: inserted_person.inbox_url.to_owned(),
332       shared_inbox_url: None,
333       matrix_user_id: None,
334     };
335
336     let read_person = Person::read(&conn, inserted_person.id).unwrap();
337     let updated_person = Person::update(&conn, inserted_person.id, &new_person).unwrap();
338     let num_deleted = Person::delete(&conn, inserted_person.id).unwrap();
339
340     assert_eq!(expected_person, read_person);
341     assert_eq!(expected_person, inserted_person);
342     assert_eq!(expected_person, updated_person);
343     assert_eq!(1, num_deleted);
344   }
345 }