]> Untitled Git - lemmy.git/blob - server/lemmy_db/src/user_view.rs
Merge remote-tracking branch 'weblate/main' into main
[lemmy.git] / server / 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::{Deserialize, 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(
55   Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize, QueryableByName, Clone,
56 )]
57 #[table_name = "user_fast"]
58 pub struct UserView {
59   pub id: i32,
60   pub actor_id: String,
61   pub name: String,
62   pub preferred_username: Option<String>,
63   pub avatar: Option<String>,
64   pub banner: Option<String>,
65   pub email: Option<String>, // TODO this shouldn't be in this view
66   pub matrix_user_id: Option<String>,
67   pub bio: Option<String>,
68   pub local: bool,
69   pub admin: bool,
70   pub banned: bool,
71   pub show_avatars: bool, // TODO this is a setting, probably doesn't need to be here
72   pub send_notifications_to_email: bool, // TODO also never used
73   pub published: chrono::NaiveDateTime,
74   pub number_of_posts: i64,
75   pub post_score: i64,
76   pub number_of_comments: i64,
77   pub comment_score: i64,
78 }
79
80 pub struct UserQueryBuilder<'a> {
81   conn: &'a PgConnection,
82   query: BoxedQuery<'a, Pg>,
83   sort: &'a SortType,
84   page: Option<i64>,
85   limit: Option<i64>,
86 }
87
88 impl<'a> UserQueryBuilder<'a> {
89   pub fn create(conn: &'a PgConnection) -> Self {
90     use super::user_view::user_fast::dsl::*;
91
92     let query = user_fast.into_boxed();
93
94     UserQueryBuilder {
95       conn,
96       query,
97       sort: &SortType::Hot,
98       page: None,
99       limit: None,
100     }
101   }
102
103   pub fn sort(mut self, sort: &'a SortType) -> Self {
104     self.sort = sort;
105     self
106   }
107
108   pub fn search_term<T: MaybeOptional<String>>(mut self, search_term: T) -> Self {
109     use super::user_view::user_fast::dsl::*;
110     if let Some(search_term) = search_term.get_optional() {
111       self.query = self.query.filter(name.ilike(fuzzy_search(&search_term)));
112     }
113     self
114   }
115
116   pub fn page<T: MaybeOptional<i64>>(mut self, page: T) -> Self {
117     self.page = page.get_optional();
118     self
119   }
120
121   pub fn limit<T: MaybeOptional<i64>>(mut self, limit: T) -> Self {
122     self.limit = limit.get_optional();
123     self
124   }
125
126   pub fn list(self) -> Result<Vec<UserView>, Error> {
127     use super::user_view::user_fast::dsl::*;
128
129     let mut query = self.query;
130
131     query = match self.sort {
132       SortType::Hot => query
133         .order_by(comment_score.desc())
134         .then_order_by(published.desc()),
135       SortType::Active => query
136         .order_by(comment_score.desc())
137         .then_order_by(published.desc()),
138       SortType::New => query.order_by(published.desc()),
139       SortType::TopAll => query.order_by(comment_score.desc()),
140       SortType::TopYear => query
141         .filter(published.gt(now - 1.years()))
142         .order_by(comment_score.desc()),
143       SortType::TopMonth => query
144         .filter(published.gt(now - 1.months()))
145         .order_by(comment_score.desc()),
146       SortType::TopWeek => query
147         .filter(published.gt(now - 1.weeks()))
148         .order_by(comment_score.desc()),
149       SortType::TopDay => query
150         .filter(published.gt(now - 1.days()))
151         .order_by(comment_score.desc()),
152     };
153
154     let (limit, offset) = limit_and_offset(self.page, self.limit);
155     query = query.limit(limit).offset(offset);
156
157     query.load::<UserView>(self.conn)
158   }
159 }
160
161 impl UserView {
162   pub fn read(conn: &PgConnection, from_user_id: i32) -> Result<Self, Error> {
163     use super::user_view::user_fast::dsl::*;
164     user_fast.find(from_user_id).first::<Self>(conn)
165   }
166
167   pub fn admins(conn: &PgConnection) -> Result<Vec<Self>, Error> {
168     use super::user_view::user_fast::dsl::*;
169     use diesel::sql_types::{Nullable, Text};
170     user_fast
171       // The select is necessary here to not get back emails
172       .select((
173         id,
174         actor_id,
175         name,
176         preferred_username,
177         avatar,
178         banner,
179         "".into_sql::<Nullable<Text>>(),
180         matrix_user_id,
181         bio,
182         local,
183         admin,
184         banned,
185         show_avatars,
186         send_notifications_to_email,
187         published,
188         number_of_posts,
189         post_score,
190         number_of_comments,
191         comment_score,
192       ))
193       .filter(admin.eq(true))
194       .order_by(published)
195       .load::<Self>(conn)
196   }
197
198   pub fn banned(conn: &PgConnection) -> Result<Vec<Self>, Error> {
199     use super::user_view::user_fast::dsl::*;
200     use diesel::sql_types::{Nullable, Text};
201     user_fast
202       .select((
203         id,
204         actor_id,
205         name,
206         preferred_username,
207         avatar,
208         banner,
209         "".into_sql::<Nullable<Text>>(),
210         matrix_user_id,
211         bio,
212         local,
213         admin,
214         banned,
215         show_avatars,
216         send_notifications_to_email,
217         published,
218         number_of_posts,
219         post_score,
220         number_of_comments,
221         comment_score,
222       ))
223       .filter(banned.eq(true))
224       .load::<Self>(conn)
225   }
226 }