backend/objects/
user.rs

1use chrono::{DateTime, Utc};
2use diesel::{ExpressionMethods, QueryDsl, Queryable, Selectable, SelectableHelper};
3use diesel_async::RunQueryDsl;
4use serde::{Deserialize, Serialize};
5use uuid::Uuid;
6
7use crate::{Conn, error::Error, objects::Me, schema::users, utils::CacheFns};
8
9use super::load_or_empty;
10
11#[derive(Deserialize, Serialize, Clone, Queryable, Selectable)]
12#[diesel(table_name = users)]
13#[diesel(check_for_backend(diesel::pg::Pg))]
14pub struct UserBuilder {
15    uuid: Uuid,
16    username: String,
17    display_name: Option<String>,
18    avatar: Option<String>,
19    pronouns: Option<String>,
20    about: Option<String>,
21    online_status: i16,
22}
23
24impl UserBuilder {
25    pub fn build(self) -> User {
26        User {
27            uuid: self.uuid,
28            username: self.username,
29            display_name: self.display_name,
30            avatar: self.avatar,
31            pronouns: self.pronouns,
32            about: self.about,
33            online_status: self.online_status,
34            friends_since: None,
35        }
36    }
37}
38
39#[derive(Deserialize, Serialize, Clone)]
40pub struct User {
41    pub uuid: Uuid,
42    username: String,
43    display_name: Option<String>,
44    avatar: Option<String>,
45    pronouns: Option<String>,
46    about: Option<String>,
47    online_status: i16,
48    pub friends_since: Option<DateTime<Utc>>,
49}
50
51impl User {
52    pub async fn fetch_one(
53        conn: &mut Conn,
54        cache_pool: &redis::Client,
55        user_uuid: Uuid,
56    ) -> Result<Self, Error> {
57        if let Ok(cache_hit) = cache_pool.get_cache_key(user_uuid.to_string()).await {
58            return Ok(cache_hit);
59        }
60
61        use users::dsl;
62        let user_builder: UserBuilder = dsl::users
63            .filter(dsl::uuid.eq(user_uuid))
64            .select(UserBuilder::as_select())
65            .get_result(conn)
66            .await?;
67
68        let user = user_builder.build();
69
70        cache_pool
71            .set_cache_key(user_uuid.to_string(), user.clone(), 1800)
72            .await?;
73
74        Ok(user)
75    }
76
77    pub async fn fetch_one_with_friendship(
78        conn: &mut Conn,
79        cache_pool: &redis::Client,
80        me: &Me,
81        user_uuid: Uuid,
82    ) -> Result<Self, Error> {
83        let mut user = Self::fetch_one(conn, cache_pool, user_uuid).await?;
84
85        if let Some(friend) = me.friends_with(conn, user_uuid).await? {
86            user.friends_since = Some(friend.accepted_at);
87        }
88
89        Ok(user)
90    }
91
92    pub async fn fetch_amount(
93        conn: &mut Conn,
94        offset: i64,
95        amount: i64,
96    ) -> Result<Vec<Self>, Error> {
97        use users::dsl;
98        let user_builders: Vec<UserBuilder> = load_or_empty(
99            dsl::users
100                .limit(amount)
101                .offset(offset)
102                .select(UserBuilder::as_select())
103                .load(conn)
104                .await,
105        )?;
106
107        let users: Vec<User> = user_builders.iter().map(|u| u.clone().build()).collect();
108
109        Ok(users)
110    }
111}