backend/objects/
role.rs

1use diesel::query_dsl::BelongingToDsl;
2use diesel::{
3    Associations, ExpressionMethods, Identifiable, Insertable, QueryDsl, Queryable, Selectable,
4    SelectableHelper, insert_into, update,
5};
6use diesel_async::RunQueryDsl;
7use serde::{Deserialize, Serialize};
8use uuid::Uuid;
9
10use crate::{
11    Conn,
12    error::Error,
13    schema::{role_members, roles},
14    utils::{CacheFns, order_by_is_above},
15};
16
17use super::{HasIsAbove, HasUuid, load_or_empty, member::MemberBuilder};
18
19#[derive(Deserialize, Serialize, Clone, Identifiable, Queryable, Selectable, Insertable)]
20#[diesel(table_name = roles)]
21#[diesel(primary_key(uuid))]
22#[diesel(check_for_backend(diesel::pg::Pg))]
23pub struct Role {
24    uuid: Uuid,
25    guild_uuid: Uuid,
26    name: String,
27    color: i32,
28    is_above: Option<Uuid>,
29    pub permissions: i64,
30}
31
32#[derive(Serialize, Clone, Identifiable, Queryable, Selectable, Insertable, Associations)]
33#[diesel(table_name = role_members)]
34#[diesel(belongs_to(MemberBuilder, foreign_key = member_uuid))]
35#[diesel(belongs_to(Role, foreign_key = role_uuid))]
36#[diesel(primary_key(role_uuid, member_uuid))]
37#[diesel(check_for_backend(diesel::pg::Pg))]
38pub struct RoleMember {
39    role_uuid: Uuid,
40    member_uuid: Uuid,
41}
42
43impl HasUuid for Role {
44    fn uuid(&self) -> &Uuid {
45        self.uuid.as_ref()
46    }
47}
48
49impl HasIsAbove for Role {
50    fn is_above(&self) -> Option<&Uuid> {
51        self.is_above.as_ref()
52    }
53}
54
55impl Role {
56    pub async fn fetch_all(conn: &mut Conn, guild_uuid: Uuid) -> Result<Vec<Self>, Error> {
57        use roles::dsl;
58        let roles: Vec<Role> = load_or_empty(
59            dsl::roles
60                .filter(dsl::guild_uuid.eq(guild_uuid))
61                .select(Role::as_select())
62                .load(conn)
63                .await,
64        )?;
65
66        Ok(roles)
67    }
68
69    pub async fn fetch_from_member(
70        conn: &mut Conn,
71        cache_pool: &redis::Client,
72        member: &MemberBuilder,
73    ) -> Result<Vec<Self>, Error> {
74        if let Ok(roles) = cache_pool
75            .get_cache_key(format!("{}_roles", member.uuid))
76            .await
77        {
78            return Ok(roles);
79        }
80
81        let roles: Vec<Role> = load_or_empty(
82            RoleMember::belonging_to(member)
83                .inner_join(roles::table)
84                .select(Role::as_select())
85                .load(conn)
86                .await,
87        )?;
88
89        cache_pool
90            .set_cache_key(format!("{}_roles", member.uuid), roles.clone(), 300)
91            .await?;
92
93        Ok(roles)
94    }
95
96    pub async fn fetch_one(conn: &mut Conn, role_uuid: Uuid) -> Result<Self, Error> {
97        use roles::dsl;
98        let role: Role = dsl::roles
99            .filter(dsl::uuid.eq(role_uuid))
100            .select(Role::as_select())
101            .get_result(conn)
102            .await?;
103
104        Ok(role)
105    }
106
107    pub async fn fetch_permissions(&self) -> Vec<Permissions> {
108        Permissions::fetch_permissions(self.permissions)
109    }
110
111    pub async fn new(conn: &mut Conn, guild_uuid: Uuid, name: String) -> Result<Self, Error> {
112        let role_uuid = Uuid::now_v7();
113
114        let roles = Self::fetch_all(conn, guild_uuid).await?;
115
116        let roles_ordered = order_by_is_above(roles).await?;
117
118        let last_role = roles_ordered.last();
119
120        let new_role = Role {
121            uuid: role_uuid,
122            guild_uuid,
123            name,
124            color: 16777215,
125            is_above: None,
126            permissions: 0,
127        };
128
129        insert_into(roles::table)
130            .values(new_role.clone())
131            .execute(conn)
132            .await?;
133
134        if let Some(old_last_role) = last_role {
135            use roles::dsl;
136            update(roles::table)
137                .filter(dsl::uuid.eq(old_last_role.uuid))
138                .set(dsl::is_above.eq(new_role.uuid))
139                .execute(conn)
140                .await?;
141        }
142
143        Ok(new_role)
144    }
145}
146
147#[derive(Clone, Copy, PartialEq, Eq)]
148pub enum Permissions {
149    /// Lets users send messages in the guild or channel
150    SendMessage = 1,
151    /// Lets users create, delete and edit channels and categories or a singular channel depending on permission context
152    ManageChannel = 2,
153    /// Lets users manage roles in the guild
154    ManageRole = 4,
155    /// Lets users create invites in the guild
156    CreateInvite = 8,
157    /// Lets users manage invites in the guild
158    ManageInvite = 16,
159    /// Lets users change guild settings
160    ManageGuild = 32,
161    /// Lets users change member settings (nickname, etc)
162    ManageMember = 64,
163    /// Lets users ban members
164    BanMember = 128,
165    /// Lets users kick members
166    KickMember = 256,
167}
168
169impl Permissions {
170    pub fn fetch_permissions(permissions: i64) -> Vec<Self> {
171        let all_perms = vec![
172            Self::SendMessage,
173            Self::ManageChannel,
174            Self::ManageRole,
175            Self::CreateInvite,
176            Self::ManageInvite,
177            Self::ManageGuild,
178            Self::ManageMember,
179            Self::BanMember,
180            Self::KickMember,
181        ];
182
183        all_perms
184            .into_iter()
185            .filter(|p| permissions & (*p as i64) != 0)
186            .collect()
187    }
188}