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