backend/objects/
member.rs

1use diesel::{
2    ExpressionMethods, Insertable, QueryDsl, Queryable, Selectable, SelectableHelper, insert_into,
3};
4use diesel_async::RunQueryDsl;
5use serde::{Deserialize, Serialize};
6use uuid::Uuid;
7
8use crate::{error::Error, objects::{Permissions, Role}, schema::guild_members, Conn, Data};
9
10use super::{User, load_or_empty};
11
12#[derive(Serialize, Queryable, Selectable, Insertable)]
13#[diesel(table_name = guild_members)]
14#[diesel(check_for_backend(diesel::pg::Pg))]
15pub struct MemberBuilder {
16    pub uuid: Uuid,
17    pub nickname: Option<String>,
18    pub user_uuid: Uuid,
19    pub guild_uuid: Uuid,
20    pub is_owner: bool,
21}
22
23impl MemberBuilder {
24    pub async fn build(&self, data: &Data) -> Result<Member, Error> {
25        let user = User::fetch_one(data, self.user_uuid).await?;
26
27        Ok(Member {
28            uuid: self.uuid,
29            nickname: self.nickname.clone(),
30            user_uuid: self.user_uuid,
31            guild_uuid: self.guild_uuid,
32            is_owner: self.is_owner,
33            user,
34        })
35    }
36
37    pub async fn check_permission(&self, data: &Data, permission: Permissions) -> Result<(), Error> {
38        if !self.is_owner {
39            let roles = Role::fetch_from_member(&data, self.uuid).await?;
40            let allowed = roles.iter().any(|r| r.permissions & permission as i64 != 0);
41            if !allowed {
42                return Err(Error::Forbidden("Not allowed".to_string()))
43            }
44        }
45
46        Ok(())
47    }
48}
49
50#[derive(Serialize, Deserialize)]
51pub struct Member {
52    pub uuid: Uuid,
53    pub nickname: Option<String>,
54    pub user_uuid: Uuid,
55    pub guild_uuid: Uuid,
56    pub is_owner: bool,
57    user: User,
58}
59
60impl Member {
61    pub async fn count(conn: &mut Conn, guild_uuid: Uuid) -> Result<i64, Error> {
62        use guild_members::dsl;
63        let count: i64 = dsl::guild_members
64            .filter(dsl::guild_uuid.eq(guild_uuid))
65            .count()
66            .get_result(conn)
67            .await?;
68
69        Ok(count)
70    }
71
72    pub async fn check_membership(
73        conn: &mut Conn,
74        user_uuid: Uuid,
75        guild_uuid: Uuid,
76    ) -> Result<MemberBuilder, Error> {
77        use guild_members::dsl;
78        let member_builder = dsl::guild_members
79            .filter(dsl::user_uuid.eq(user_uuid))
80            .filter(dsl::guild_uuid.eq(guild_uuid))
81            .select(MemberBuilder::as_select())
82            .get_result(conn)
83            .await?;
84
85        Ok(member_builder)
86    }
87
88    pub async fn fetch_one(data: &Data, user_uuid: Uuid, guild_uuid: Uuid) -> Result<Self, Error> {
89        let mut conn = data.pool.get().await?;
90
91        use guild_members::dsl;
92        let member: MemberBuilder = dsl::guild_members
93            .filter(dsl::user_uuid.eq(user_uuid))
94            .filter(dsl::guild_uuid.eq(guild_uuid))
95            .select(MemberBuilder::as_select())
96            .get_result(&mut conn)
97            .await?;
98
99        member.build(data).await
100    }
101
102    pub async fn fetch_all(data: &Data, guild_uuid: Uuid) -> Result<Vec<Self>, Error> {
103        let mut conn = data.pool.get().await?;
104
105        use guild_members::dsl;
106        let member_builders: Vec<MemberBuilder> = load_or_empty(
107            dsl::guild_members
108                .filter(dsl::guild_uuid.eq(guild_uuid))
109                .select(MemberBuilder::as_select())
110                .load(&mut conn)
111                .await,
112        )?;
113
114        let member_futures = member_builders
115            .iter()
116            .map(async move |m| m.build(data).await);
117
118        futures::future::try_join_all(member_futures).await
119    }
120
121    pub async fn new(data: &Data, user_uuid: Uuid, guild_uuid: Uuid) -> Result<Self, Error> {
122        let mut conn = data.pool.get().await?;
123
124        let member_uuid = Uuid::now_v7();
125
126        let member = MemberBuilder {
127            uuid: member_uuid,
128            guild_uuid,
129            user_uuid,
130            nickname: None,
131            is_owner: false,
132        };
133
134        insert_into(guild_members::table)
135            .values(&member)
136            .execute(&mut conn)
137            .await?;
138
139        member.build(data).await
140    }
141}