]> Untitled Git - lemmy.git/blob - lemmy_db/src/user_view.rs
Isomorphic docker (#1124)
[lemmy.git] / lemmy_db / src / user_view.rs
1 use super::user_view::user_fast::BoxedQuery;
2 use crate::{fuzzy_search, limit_and_offset, MaybeOptional, SortType};
3 use diesel::{dsl::*, pg::Pg, result::Error, *};
4 use serde::Serialize;
5
6 table! {
7   user_view (id) {
8     id -> Int4,
9     actor_id -> Text,
10     name -> Varchar,
11     preferred_username -> Nullable<Varchar>,
12     avatar -> Nullable<Text>,
13     banner -> Nullable<Text>,
14     email -> Nullable<Text>,
15     matrix_user_id -> Nullable<Text>,
16     bio -> Nullable<Text>,
17     local -> Bool,
18     admin -> Bool,
19     banned -> Bool,
20     show_avatars -> Bool,
21     send_notifications_to_email -> Bool,
22     published -> Timestamp,
23     number_of_posts -> BigInt,
24     post_score -> BigInt,
25     number_of_comments -> BigInt,
26     comment_score -> BigInt,
27   }
28 }
29
30 table! {
31   user_fast (id) {
32     id -> Int4,
33     actor_id -> Text,
34     name -> Varchar,
35     preferred_username -> Nullable<Varchar>,
36     avatar -> Nullable<Text>,
37     banner -> Nullable<Text>,
38     email -> Nullable<Text>,
39     matrix_user_id -> Nullable<Text>,
40     bio -> Nullable<Text>,
41     local -> Bool,
42     admin -> Bool,
43     banned -> Bool,
44     show_avatars -> Bool,
45     send_notifications_to_email -> Bool,
46     published -> Timestamp,
47     number_of_posts -> BigInt,
48     post_score -> BigInt,
49     number_of_comments -> BigInt,
50     comment_score -> BigInt,
51   }
52 }
53
54 #[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, QueryableByName, Clone)]
55 #[table_name = "user_fast"]
56 pub struct UserView {
57   pub id: i32,
58   pub actor_id: String,
59   pub name: String,
60   pub preferred_username: Option<String>,
61   pub avatar: Option<String>,
62   pub banner: Option<String>,
63   pub email: Option<String>, // TODO this shouldn't be in this view
64   pub matrix_user_id: Option<String>,
65   pub bio: Option<String>,
66   pub local: bool,
67   pub admin: bool,
68   pub banned: bool,
69   pub show_avatars: bool, // TODO this is a setting, probably doesn't need to be here
70   pub send_notifications_to_email: bool, // TODO also never used
71   pub published: chrono::NaiveDateTime,
72   pub number_of_posts: i64,
73   pub post_score: i64,
74   pub number_of_comments: i64,
75   pub comment_score: i64,
76 }
77
78 pub struct UserQueryBuilder<'a> {
79   conn: &'a PgConnection,
80   query: BoxedQuery<'a, Pg>,
81   sort: &'a SortType,
82   page: Option<i64>,
83   limit: Option<i64>,
84 }
85
86 impl<'a> UserQueryBuilder<'a> {
87   pub fn create(conn: &'a PgConnection) -> Self {
88     use super::user_view::user_fast::dsl::*;
89
90     let query = user_fast.into_boxed();
91
92     UserQueryBuilder {
93       conn,
94       query,
95       sort: &SortType::Hot,
96       page: None,
97       limit: None,
98     }
99   }
100
101   pub fn sort(mut self, sort: &'a SortType) -> Self {
102     self.sort = sort;
103     self
104   }
105
106   pub fn search_term<T: MaybeOptional<String>>(mut self, search_term: T) -> Self {
107     use super::user_view::user_fast::dsl::*;
108     if let Some(search_term) = search_term.get_optional() {
109       self.query = self.query.filter(name.ilike(fuzzy_search(&search_term)));
110     }
111     self
112   }
113
114   pub fn page<T: MaybeOptional<i64>>(mut self, page: T) -> Self {
115     self.page = page.get_optional();
116     self
117   }
118
119   pub fn limit<T: MaybeOptional<i64>>(mut self, limit: T) -> Self {
120     self.limit = limit.get_optional();
121     self
122   }
123
124   pub fn list(self) -> Result<Vec<UserView>, Error> {
125     use super::user_view::user_fast::dsl::*;
126     use diesel::sql_types::{Nullable, Text};
127
128     let mut query = self.query;
129
130     query = match self.sort {
131       SortType::Hot => query
132         .order_by(comment_score.desc())
133         .then_order_by(published.desc()),
134       SortType::Active => query
135         .order_by(comment_score.desc())
136         .then_order_by(published.desc()),
137       SortType::New => query.order_by(published.desc()),
138       SortType::TopAll => query.order_by(comment_score.desc()),
139       SortType::TopYear => query
140         .filter(published.gt(now - 1.years()))
141         .order_by(comment_score.desc()),
142       SortType::TopMonth => query
143         .filter(published.gt(now - 1.months()))
144         .order_by(comment_score.desc()),
145       SortType::TopWeek => query
146         .filter(published.gt(now - 1.weeks()))
147         .order_by(comment_score.desc()),
148       SortType::TopDay => query
149         .filter(published.gt(now - 1.days()))
150         .order_by(comment_score.desc()),
151     };
152
153     let (limit, offset) = limit_and_offset(self.page, self.limit);
154     query = query.limit(limit).offset(offset);
155
156     // The select is necessary here to not get back emails
157     query = query.select((
158       id,
159       actor_id,
160       name,
161       preferred_username,
162       avatar,
163       banner,
164       "".into_sql::<Nullable<Text>>(),
165       matrix_user_id,
166       bio,
167       local,
168       admin,
169       banned,
170       show_avatars,
171       send_notifications_to_email,
172       published,
173       number_of_posts,
174       post_score,
175       number_of_comments,
176       comment_score,
177     ));
178     query.load::<UserView>(self.conn)
179   }
180 }
181
182 impl UserView {
183   pub fn admins(conn: &PgConnection) -> Result<Vec<Self>, Error> {
184     use super::user_view::user_fast::dsl::*;
185     use diesel::sql_types::{Nullable, Text};
186     user_fast
187       // The select is necessary here to not get back emails
188       .select((
189         id,
190         actor_id,
191         name,
192         preferred_username,
193         avatar,
194         banner,
195         "".into_sql::<Nullable<Text>>(),
196         matrix_user_id,
197         bio,
198         local,
199         admin,
200         banned,
201         show_avatars,
202         send_notifications_to_email,
203         published,
204         number_of_posts,
205         post_score,
206         number_of_comments,
207         comment_score,
208       ))
209       .filter(admin.eq(true))
210       .order_by(published)
211       .load::<Self>(conn)
212   }
213
214   pub fn banned(conn: &PgConnection) -> Result<Vec<Self>, Error> {
215     use super::user_view::user_fast::dsl::*;
216     use diesel::sql_types::{Nullable, Text};
217     user_fast
218       .select((
219         id,
220         actor_id,
221         name,
222         preferred_username,
223         avatar,
224         banner,
225         "".into_sql::<Nullable<Text>>(),
226         matrix_user_id,
227         bio,
228         local,
229         admin,
230         banned,
231         show_avatars,
232         send_notifications_to_email,
233         published,
234         number_of_posts,
235         post_score,
236         number_of_comments,
237         comment_score,
238       ))
239       .filter(banned.eq(true))
240       .load::<Self>(conn)
241   }
242
243   pub fn get_user_secure(conn: &PgConnection, user_id: i32) -> Result<Self, Error> {
244     use super::user_view::user_fast::dsl::*;
245     use diesel::sql_types::{Nullable, Text};
246     user_fast
247       .select((
248         id,
249         actor_id,
250         name,
251         preferred_username,
252         avatar,
253         banner,
254         "".into_sql::<Nullable<Text>>(),
255         matrix_user_id,
256         bio,
257         local,
258         admin,
259         banned,
260         show_avatars,
261         send_notifications_to_email,
262         published,
263         number_of_posts,
264         post_score,
265         number_of_comments,
266         comment_score,
267       ))
268       .find(user_id)
269       .first::<Self>(conn)
270   }
271 }