]> Untitled Git - lemmy.git/blob - crates/db_schema/src/impls/person.rs
Moving settings to Database. (#2492)
[lemmy.git] / crates / db_schema / src / impls / person.rs
1 use crate::{
2   newtypes::{DbUrl, PersonId},
3   schema::person::dsl::*,
4   source::person::{Person, PersonInsertForm, PersonUpdateForm},
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     instance_id,
41   );
42
43   impl ToSafe for Person {
44     type SafeColumns = Columns;
45     fn safe_columns_tuple() -> Self::SafeColumns {
46       (
47         id,
48         name,
49         display_name,
50         avatar,
51         banned,
52         published,
53         updated,
54         actor_id,
55         bio,
56         local,
57         banner,
58         deleted,
59         inbox_url,
60         shared_inbox_url,
61         matrix_user_id,
62         admin,
63         bot_account,
64         ban_expires,
65         instance_id,
66       )
67     }
68   }
69 }
70
71 impl Crud for Person {
72   type InsertForm = PersonInsertForm;
73   type UpdateForm = PersonUpdateForm;
74   type IdType = PersonId;
75   fn read(conn: &mut PgConnection, person_id: PersonId) -> Result<Self, Error> {
76     person
77       .filter(deleted.eq(false))
78       .find(person_id)
79       .first::<Self>(conn)
80   }
81   fn delete(conn: &mut PgConnection, person_id: PersonId) -> Result<usize, Error> {
82     diesel::delete(person.find(person_id)).execute(conn)
83   }
84   fn create(conn: &mut PgConnection, form: &PersonInsertForm) -> Result<Self, Error> {
85     insert_into(person)
86       .values(form)
87       .on_conflict(actor_id)
88       .do_update()
89       .set(form)
90       .get_result::<Self>(conn)
91   }
92   fn update(
93     conn: &mut PgConnection,
94     person_id: PersonId,
95     form: &PersonUpdateForm,
96   ) -> Result<Self, Error> {
97     diesel::update(person.find(person_id))
98       .set(form)
99       .get_result::<Self>(conn)
100   }
101 }
102
103 impl Person {
104   pub fn delete_account(conn: &mut PgConnection, person_id: PersonId) -> Result<Person, Error> {
105     use crate::schema::local_user;
106
107     // Set the local user info to none
108     diesel::update(local_user::table.filter(local_user::person_id.eq(person_id)))
109       .set((
110         local_user::email.eq::<Option<String>>(None),
111         local_user::validator_time.eq(naive_now()),
112       ))
113       .execute(conn)?;
114
115     diesel::update(person.find(person_id))
116       .set((
117         display_name.eq::<Option<String>>(None),
118         avatar.eq::<Option<String>>(None),
119         banner.eq::<Option<String>>(None),
120         bio.eq::<Option<String>>(None),
121         matrix_user_id.eq::<Option<String>>(None),
122         deleted.eq(true),
123         updated.eq(naive_now()),
124       ))
125       .get_result::<Self>(conn)
126   }
127 }
128
129 pub fn is_banned(banned_: bool, expires: Option<chrono::NaiveDateTime>) -> bool {
130   if let Some(expires) = expires {
131     banned_ && expires.gt(&naive_now())
132   } else {
133     banned_
134   }
135 }
136
137 impl ApubActor for Person {
138   fn read_from_apub_id(conn: &mut PgConnection, object_id: &DbUrl) -> Result<Option<Self>, Error> {
139     use crate::schema::person::dsl::*;
140     Ok(
141       person
142         .filter(deleted.eq(false))
143         .filter(actor_id.eq(object_id))
144         .first::<Person>(conn)
145         .ok()
146         .map(Into::into),
147     )
148   }
149
150   fn read_from_name(
151     conn: &mut PgConnection,
152     from_name: &str,
153     include_deleted: bool,
154   ) -> Result<Person, Error> {
155     let mut q = person
156       .into_boxed()
157       .filter(local.eq(true))
158       .filter(lower(name).eq(lower(from_name)));
159     if !include_deleted {
160       q = q.filter(deleted.eq(false))
161     }
162     q.first::<Self>(conn)
163   }
164
165   fn read_from_name_and_domain(
166     conn: &mut PgConnection,
167     person_name: &str,
168     protocol_domain: &str,
169   ) -> Result<Person, Error> {
170     use crate::schema::person::dsl::*;
171     person
172       .filter(lower(name).eq(lower(person_name)))
173       .filter(actor_id.like(format!("{}%", protocol_domain)))
174       .first::<Self>(conn)
175   }
176 }
177
178 #[cfg(test)]
179 mod tests {
180   use crate::{
181     source::{instance::Instance, person::*},
182     traits::Crud,
183     utils::establish_unpooled_connection,
184   };
185   use serial_test::serial;
186
187   #[test]
188   #[serial]
189   fn test_crud() {
190     let conn = &mut establish_unpooled_connection();
191
192     let inserted_instance = Instance::create(conn, "my_domain.tld").unwrap();
193
194     let new_person = PersonInsertForm::builder()
195       .name("holly".into())
196       .public_key("nada".to_owned())
197       .instance_id(inserted_instance.id)
198       .build();
199
200     let inserted_person = Person::create(conn, &new_person).unwrap();
201
202     let expected_person = Person {
203       id: inserted_person.id,
204       name: "holly".into(),
205       display_name: None,
206       avatar: None,
207       banner: None,
208       banned: false,
209       deleted: false,
210       published: inserted_person.published,
211       updated: None,
212       actor_id: inserted_person.actor_id.to_owned(),
213       bio: None,
214       local: true,
215       bot_account: false,
216       admin: false,
217       private_key: None,
218       public_key: "nada".to_owned(),
219       last_refreshed_at: inserted_person.published,
220       inbox_url: inserted_person.inbox_url.to_owned(),
221       shared_inbox_url: None,
222       matrix_user_id: None,
223       ban_expires: None,
224       instance_id: inserted_instance.id,
225     };
226
227     let read_person = Person::read(conn, inserted_person.id).unwrap();
228
229     let update_person_form = PersonUpdateForm::builder()
230       .actor_id(Some(inserted_person.actor_id.to_owned()))
231       .build();
232     let updated_person = Person::update(conn, inserted_person.id, &update_person_form).unwrap();
233
234     let num_deleted = Person::delete(conn, inserted_person.id).unwrap();
235     Instance::delete(conn, inserted_instance.id).unwrap();
236
237     assert_eq!(expected_person, read_person);
238     assert_eq!(expected_person, inserted_person);
239     assert_eq!(expected_person, updated_person);
240     assert_eq!(1, num_deleted);
241   }
242 }