]> Untitled Git - lemmy.git/blob - crates/db_schema/src/impls/person.rs
Diesel 2.0.0 upgrade (#2452)
[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 impl Crud for Person {
70   type Form = PersonForm;
71   type IdType = PersonId;
72   fn read(conn: &mut PgConnection, person_id: PersonId) -> Result<Self, Error> {
73     person
74       .filter(deleted.eq(false))
75       .find(person_id)
76       .first::<Self>(conn)
77   }
78   fn delete(conn: &mut PgConnection, person_id: PersonId) -> Result<usize, Error> {
79     diesel::delete(person.find(person_id)).execute(conn)
80   }
81   fn create(conn: &mut PgConnection, form: &PersonForm) -> Result<Self, Error> {
82     insert_into(person).values(form).get_result::<Self>(conn)
83   }
84   fn update(
85     conn: &mut PgConnection,
86     person_id: PersonId,
87     form: &PersonForm,
88   ) -> Result<Self, Error> {
89     diesel::update(person.find(person_id))
90       .set(form)
91       .get_result::<Self>(conn)
92   }
93 }
94
95 impl Person {
96   pub fn ban_person(
97     conn: &mut PgConnection,
98     person_id: PersonId,
99     ban: bool,
100     expires: Option<chrono::NaiveDateTime>,
101   ) -> Result<Self, Error> {
102     diesel::update(person.find(person_id))
103       .set((banned.eq(ban), ban_expires.eq(expires)))
104       .get_result::<Self>(conn)
105   }
106
107   pub fn add_admin(
108     conn: &mut PgConnection,
109     person_id: PersonId,
110     added: bool,
111   ) -> Result<Self, Error> {
112     diesel::update(person.find(person_id))
113       .set(admin.eq(added))
114       .get_result::<Self>(conn)
115   }
116
117   pub fn mark_as_updated(conn: &mut PgConnection, person_id: PersonId) -> Result<Person, Error> {
118     diesel::update(person.find(person_id))
119       .set((last_refreshed_at.eq(naive_now()),))
120       .get_result::<Self>(conn)
121   }
122
123   pub fn delete_account(conn: &mut PgConnection, person_id: PersonId) -> Result<Person, Error> {
124     use crate::schema::local_user;
125
126     // Set the local user info to none
127     diesel::update(local_user::table.filter(local_user::person_id.eq(person_id)))
128       .set((
129         local_user::email.eq::<Option<String>>(None),
130         local_user::validator_time.eq(naive_now()),
131       ))
132       .execute(conn)?;
133
134     diesel::update(person.find(person_id))
135       .set((
136         display_name.eq::<Option<String>>(None),
137         avatar.eq::<Option<String>>(None),
138         banner.eq::<Option<String>>(None),
139         bio.eq::<Option<String>>(None),
140         matrix_user_id.eq::<Option<String>>(None),
141         deleted.eq(true),
142         updated.eq(naive_now()),
143       ))
144       .get_result::<Self>(conn)
145   }
146
147   pub fn upsert(conn: &mut PgConnection, person_form: &PersonForm) -> Result<Person, Error> {
148     insert_into(person)
149       .values(person_form)
150       .on_conflict(actor_id)
151       .do_update()
152       .set(person_form)
153       .get_result::<Self>(conn)
154   }
155
156   pub fn update_deleted(
157     conn: &mut PgConnection,
158     person_id: PersonId,
159     new_deleted: bool,
160   ) -> Result<Person, Error> {
161     use crate::schema::person::dsl::*;
162     diesel::update(person.find(person_id))
163       .set(deleted.eq(new_deleted))
164       .get_result::<Self>(conn)
165   }
166
167   pub fn leave_admin(conn: &mut PgConnection, person_id: PersonId) -> Result<Self, Error> {
168     diesel::update(person.find(person_id))
169       .set(admin.eq(false))
170       .get_result::<Self>(conn)
171   }
172
173   pub fn remove_avatar_and_banner(
174     conn: &mut PgConnection,
175     person_id: PersonId,
176   ) -> Result<Self, Error> {
177     diesel::update(person.find(person_id))
178       .set((
179         avatar.eq::<Option<String>>(None),
180         banner.eq::<Option<String>>(None),
181       ))
182       .get_result::<Self>(conn)
183   }
184 }
185
186 pub fn is_banned(banned_: bool, expires: Option<chrono::NaiveDateTime>) -> bool {
187   if let Some(expires) = expires {
188     banned_ && expires.gt(&naive_now())
189   } else {
190     banned_
191   }
192 }
193
194 impl ApubActor for Person {
195   fn read_from_apub_id(conn: &mut PgConnection, object_id: &DbUrl) -> Result<Option<Self>, Error> {
196     use crate::schema::person::dsl::*;
197     Ok(
198       person
199         .filter(deleted.eq(false))
200         .filter(actor_id.eq(object_id))
201         .first::<Person>(conn)
202         .ok()
203         .map(Into::into),
204     )
205   }
206
207   fn read_from_name(
208     conn: &mut PgConnection,
209     from_name: &str,
210     include_deleted: bool,
211   ) -> Result<Person, Error> {
212     let mut q = person
213       .into_boxed()
214       .filter(local.eq(true))
215       .filter(lower(name).eq(lower(from_name)));
216     if !include_deleted {
217       q = q.filter(deleted.eq(false))
218     }
219     q.first::<Self>(conn)
220   }
221
222   fn read_from_name_and_domain(
223     conn: &mut PgConnection,
224     person_name: &str,
225     protocol_domain: &str,
226   ) -> Result<Person, Error> {
227     use crate::schema::person::dsl::*;
228     person
229       .filter(lower(name).eq(lower(person_name)))
230       .filter(actor_id.like(format!("{}%", protocol_domain)))
231       .first::<Self>(conn)
232   }
233 }
234
235 #[cfg(test)]
236 mod tests {
237   use crate::{source::person::*, traits::Crud, utils::establish_unpooled_connection};
238
239   #[test]
240   fn test_crud() {
241     let conn = &mut establish_unpooled_connection();
242
243     let new_person = PersonForm {
244       name: "holly".into(),
245       public_key: Some("nada".to_owned()),
246       ..PersonForm::default()
247     };
248
249     let inserted_person = Person::create(conn, &new_person).unwrap();
250
251     let expected_person = Person {
252       id: inserted_person.id,
253       name: "holly".into(),
254       display_name: None,
255       avatar: None,
256       banner: None,
257       banned: false,
258       deleted: false,
259       published: inserted_person.published,
260       updated: None,
261       actor_id: inserted_person.actor_id.to_owned(),
262       bio: None,
263       local: true,
264       bot_account: false,
265       admin: false,
266       private_key: None,
267       public_key: "nada".to_owned(),
268       last_refreshed_at: inserted_person.published,
269       inbox_url: inserted_person.inbox_url.to_owned(),
270       shared_inbox_url: None,
271       matrix_user_id: None,
272       ban_expires: None,
273     };
274
275     let read_person = Person::read(conn, inserted_person.id).unwrap();
276     let updated_person = Person::update(conn, inserted_person.id, &new_person).unwrap();
277     let num_deleted = Person::delete(conn, inserted_person.id).unwrap();
278
279     assert_eq!(expected_person, read_person);
280     assert_eq!(expected_person, inserted_person);
281     assert_eq!(expected_person, updated_person);
282     assert_eq!(1, num_deleted);
283   }
284 }