Naposledy aktivní 1723995325

rootspring's Avatar rootspring revidoval tento gist 1723995325. Přejít na revizi

1 file changed, 179 insertions

member.rs(vytvořil soubor)

@@ -0,0 +1,179 @@
1 + use kittycat::perms::Permission;
2 + use serenity::all::{GuildId, RoleId, UserId};
3 +
4 + /// Rederive permissions rederives the permissions given a member id and a list of roles
5 + ///
6 + /// Calling rederive_perms has some side-effects
7 + ///
8 + /// 0. The member will automatically be added to the guild_members table if they are not already in it
9 + /// 1. Resolved_perms_cache will be updated in the guild_members table
10 + pub async fn rederive_perms(
11 + pool: &sqlx::PgPool,
12 + guild_id: GuildId,
13 + user_id: UserId,
14 + roles: &[RoleId],
15 + ) -> Result<Vec<Permission>, crate::Error> {
16 + let roles_str = {
17 + let mut r = Vec::new();
18 +
19 + for role in roles {
20 + r.push(role.to_string());
21 + }
22 +
23 + r.push(guild_id.everyone_role().to_string());
24 +
25 + r
26 + };
27 +
28 + let mut tx = pool.begin().await?;
29 +
30 + let rec = sqlx::query!(
31 + "SELECT perm_overrides FROM guild_members WHERE guild_id = $1 AND user_id = $2",
32 + guild_id.to_string(),
33 + user_id.to_string()
34 + )
35 + .fetch_optional(&mut *tx)
36 + .await?;
37 +
38 + // Rederive permissions for the new perms
39 + let role_perms = sqlx::query!(
40 + "SELECT role_id, perms, index FROM guild_roles WHERE guild_id = $1 AND role_id = ANY($2)",
41 + guild_id.to_string(),
42 + &roles_str
43 + )
44 + .fetch_all(&mut *tx)
45 + .await?;
46 +
47 + let mut user_positions = Vec::new();
48 +
49 + for role in role_perms {
50 + user_positions.push(kittycat::perms::PartialStaffPosition {
51 + id: role.role_id,
52 + perms: role
53 + .perms
54 + .iter()
55 + .map(|x| Permission::from_string(x))
56 + .collect(),
57 + index: role.index,
58 + })
59 + }
60 +
61 + let (in_db, perm_overrides) = if let Some(rec) = rec {
62 + (
63 + true,
64 + rec.perm_overrides
65 + .iter()
66 + .map(|x| Permission::from_string(x))
67 + .collect(),
68 + )
69 + } else {
70 + (false, Vec::new())
71 + };
72 +
73 + let resolved_perms = kittycat::perms::StaffPermissions {
74 + user_positions,
75 + perm_overrides,
76 + }
77 + .resolve();
78 +
79 + let resolved_perms_str = resolved_perms
80 + .iter()
81 + .map(|x| x.to_string())
82 + .collect::<Vec<String>>();
83 +
84 + if in_db {
85 + sqlx::query!(
86 + "UPDATE guild_members SET roles = $1, resolved_perms_cache = $2, needs_perm_rederive = false WHERE guild_id = $3 AND user_id = $4",
87 + &roles_str,
88 + &resolved_perms_str,
89 + guild_id.to_string(),
90 + user_id.to_string()
91 + )
92 + .execute(&mut *tx)
93 + .await?;
94 + } else {
95 + // Check if guild is in the guilds table
96 + let guild_exists = sqlx::query!(
97 + "SELECT COUNT(*) FROM guilds WHERE id = $1",
98 + guild_id.to_string()
99 + )
100 + .fetch_one(&mut *tx)
101 + .await?;
102 +
103 + if guild_exists.count.unwrap_or_default() == 0 {
104 + sqlx::query!("INSERT INTO guilds (id) VALUES ($1)", guild_id.to_string())
105 + .execute(&mut *tx)
106 + .await?;
107 + }
108 +
109 + sqlx::query!(
110 + "INSERT INTO guild_members (guild_id, user_id, roles, resolved_perms_cache) VALUES ($1, $2, $3, $4)",
111 + guild_id.to_string(),
112 + user_id.to_string(),
113 + &roles_str,
114 + &resolved_perms_str
115 + )
116 + .execute(&mut *tx)
117 + .await?;
118 + }
119 +
120 + tx.commit().await?;
121 +
122 + Ok(resolved_perms)
123 + }
124 +
125 + /// Returns the kittycat permissions of a user. This function also takes into account permission overrides etc.
126 + pub async fn get_kittycat_perms(
127 + pool: &sqlx::PgPool,
128 + guild_id: GuildId,
129 + guild_owner_id: UserId,
130 + user_id: UserId,
131 + roles: &[RoleId],
132 + ) -> Result<Vec<Permission>, crate::Error> {
133 + // For now, owners have full permission, this may change in the future (maybe??)
134 + if guild_owner_id == user_id {
135 + return Ok(vec!["global.*".into()]);
136 + }
137 +
138 + let everyone_role = guild_id.everyone_role();
139 +
140 + let rec = sqlx::query!("SELECT roles, needs_perm_rederive, resolved_perms_cache, perm_overrides FROM guild_members WHERE guild_id = $1 AND user_id = $2", guild_id.to_string(), user_id.to_string())
141 + .fetch_optional(pool)
142 + .await?;
143 +
144 + if let Some(rec) = rec {
145 + if rec.needs_perm_rederive {
146 + return rederive_perms(pool, guild_id, user_id, roles).await;
147 + }
148 +
149 + // Check user roles against db roles
150 + let db_roles = rec.roles;
151 +
152 + let mut roles_changed = false;
153 +
154 + for role in roles {
155 + if !db_roles.contains(&role.to_string()) {
156 + roles_changed = true;
157 + break;
158 + }
159 + }
160 +
161 + // Check everyone role too
162 + if !db_roles.contains(&everyone_role.to_string()) {
163 + roles_changed = true;
164 + }
165 +
166 + if !roles_changed {
167 + Ok(rec
168 + .resolved_perms_cache
169 + .iter()
170 + .map(|x| Permission::from_string(x))
171 + .collect::<Vec<Permission>>()) // Then use the resolved perms cache
172 + } else {
173 + Ok(rederive_perms(pool, guild_id, user_id, roles).await?)
174 + }
175 + } else {
176 + // They have no column in db, we cannot have a fast-path as the everyone role may have permissions
177 + Ok(rederive_perms(pool, guild_id, user_id, roles).await?)
178 + }
179 + }
Novější Starší