quick.rs
· 5.2 KiB · Rust
Bruto
use serde::{Deserialize, Serialize};
use std::collections::HashSet;
/// The base permissions for quick lockdown
static BASE_PERMS: [serenity::model::permissions::Permissions; 3] = [
serenity::all::Permissions::VIEW_CHANNEL,
serenity::all::Permissions::SEND_MESSAGES,
serenity::all::Permissions::SEND_MESSAGES_IN_THREADS,
];
/// The result of a `test_quick_lockdown` call
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct QuickLockdownTestResult {
/// Which roles need to be changed/fixed combined with the permissions they are missing
pub changes_needed:
std::collections::HashMap<serenity::all::RoleId, serenity::all::Permissions>,
/// The critical roles (either member roles or the `@everyone` role)
pub critical_roles: HashSet<serenity::all::RoleId>,
}
/// Returns the critical roles given a [PartialGuild](`serenity::all::PartialGuild`) and a set of member roles
pub fn get_critical_roles(
pg: &serenity::all::PartialGuild,
member_roles: HashSet<serenity::all::RoleId>,
) -> Result<HashSet<serenity::all::RoleId>, silverpelt::Error> {
if member_roles.is_empty() {
// Find the everyone role
let everyone_role = pg
.roles
.iter()
.find(|r| r.id.get() == pg.id.get())
.ok_or_else(|| silverpelt::Error::from("No @everyone role found"))?;
Ok(std::iter::once(everyone_role.id).collect())
} else {
Ok(member_roles)
}
}
/// Given a [PartialGuild](`serenity::all::PartialGuild`) and a set of member roles, `test_quick_lockdown` will check if the guild meets the requirements for quick lockdown.
///
/// The requirements for quick lockdown are listed in README.md and the basic idea is listed below:
///
/// - One can define a set of critical roles which are either the member roles or the ``@everyone`` role, all other roles must not have View Channel, Send Messages and/or Send Messages In Threads permissions
pub async fn test_quick_lockdown(
pg: &serenity::all::PartialGuild,
member_roles: HashSet<serenity::all::RoleId>,
) -> Result<QuickLockdownTestResult, silverpelt::Error> {
let critical_roles = get_critical_roles(pg, member_roles)?;
let mut changes_needed = std::collections::HashMap::new();
// From here on out, we only need to care about critical and non critical roles
for role in pg.roles.iter() {
if critical_roles.contains(&role.id) {
let mut needed_perms = serenity::all::Permissions::empty();
let mut missing = false;
for perm in BASE_PERMS {
if !role.permissions.contains(perm) {
needed_perms |= perm;
missing = true;
}
}
if missing {
changes_needed.insert(role.id, needed_perms);
}
}
}
Ok(QuickLockdownTestResult {
changes_needed,
critical_roles,
})
}
/// Creates a new quick lockdown given a [PartialGuild](`serenity::all::PartialGuild`) and a set of critical roles
///
/// This is achieved by **removing** the `BASE_PERMS` from the critical roles
pub async fn create_quick_lockdown(
ctx: &serenity::client::Context,
pg: &mut serenity::all::PartialGuild,
critical_roles: HashSet<serenity::all::RoleId>,
) -> Result<(), silverpelt::Error> {
let mut new_roles = Vec::new();
for role in pg.roles.iter() {
if critical_roles.contains(&role.id) {
let mut perms = role.permissions;
for perm in BASE_PERMS {
perms.remove(perm);
}
new_roles.push(
pg.id
.edit_role(
&ctx.http,
role.id,
serenity::all::EditRole::new().permissions(perms),
)
.await?,
);
}
}
for role in new_roles {
pg.roles.insert(role);
}
Ok(())
}
/// Reverts a quick lockdown given a [PartialGuild](`serenity::all::PartialGuild`) and a set of critical roles
///
/// This is achieved by **adding** the `BASE_PERMS` to the critical roles
pub async fn revert_quick_lockdown(
ctx: &serenity::client::Context,
pg: &mut serenity::all::PartialGuild,
critical_roles: HashSet<serenity::all::RoleId>,
) -> Result<(), silverpelt::Error> {
let mut new_roles = Vec::new();
for role in pg.roles.iter() {
if critical_roles.contains(&role.id) {
let mut perms = role.permissions;
let mut changed = false;
for perm in BASE_PERMS {
if !perms.contains(perm) {
changed = true;
perms |= perm;
}
}
if !changed {
continue; // Avoid useless API call when no changes are needed
}
new_roles.push(
pg.id
.edit_role(
&ctx.http,
role.id,
serenity::all::EditRole::new().permissions(perms),
)
.await?,
);
}
}
for role in new_roles {
pg.roles.insert(role);
}
Ok(())
}
1 | use serde::{Deserialize, Serialize}; |
2 | use std::collections::HashSet; |
3 | |
4 | /// The base permissions for quick lockdown |
5 | static BASE_PERMS: [serenity::model::permissions::Permissions; 3] = [ |
6 | serenity::all::Permissions::VIEW_CHANNEL, |
7 | serenity::all::Permissions::SEND_MESSAGES, |
8 | serenity::all::Permissions::SEND_MESSAGES_IN_THREADS, |
9 | ]; |
10 | |
11 | /// The result of a `test_quick_lockdown` call |
12 | #[derive(Debug, Serialize, Deserialize, Clone)] |
13 | pub struct QuickLockdownTestResult { |
14 | /// Which roles need to be changed/fixed combined with the permissions they are missing |
15 | pub changes_needed: |
16 | std::collections::HashMap<serenity::all::RoleId, serenity::all::Permissions>, |
17 | /// The critical roles (either member roles or the `@everyone` role) |
18 | pub critical_roles: HashSet<serenity::all::RoleId>, |
19 | } |
20 | |
21 | /// Returns the critical roles given a [PartialGuild](`serenity::all::PartialGuild`) and a set of member roles |
22 | pub fn get_critical_roles( |
23 | pg: &serenity::all::PartialGuild, |
24 | member_roles: HashSet<serenity::all::RoleId>, |
25 | ) -> Result<HashSet<serenity::all::RoleId>, silverpelt::Error> { |
26 | if member_roles.is_empty() { |
27 | // Find the everyone role |
28 | let everyone_role = pg |
29 | .roles |
30 | .iter() |
31 | .find(|r| r.id.get() == pg.id.get()) |
32 | .ok_or_else(|| silverpelt::Error::from("No @everyone role found"))?; |
33 | |
34 | Ok(std::iter::once(everyone_role.id).collect()) |
35 | } else { |
36 | Ok(member_roles) |
37 | } |
38 | } |
39 | |
40 | /// Given a [PartialGuild](`serenity::all::PartialGuild`) and a set of member roles, `test_quick_lockdown` will check if the guild meets the requirements for quick lockdown. |
41 | /// |
42 | /// The requirements for quick lockdown are listed in README.md and the basic idea is listed below: |
43 | /// |
44 | /// - One can define a set of critical roles which are either the member roles or the ``@everyone`` role, all other roles must not have View Channel, Send Messages and/or Send Messages In Threads permissions |
45 | pub async fn test_quick_lockdown( |
46 | pg: &serenity::all::PartialGuild, |
47 | member_roles: HashSet<serenity::all::RoleId>, |
48 | ) -> Result<QuickLockdownTestResult, silverpelt::Error> { |
49 | let critical_roles = get_critical_roles(pg, member_roles)?; |
50 | |
51 | let mut changes_needed = std::collections::HashMap::new(); |
52 | |
53 | // From here on out, we only need to care about critical and non critical roles |
54 | for role in pg.roles.iter() { |
55 | if critical_roles.contains(&role.id) { |
56 | let mut needed_perms = serenity::all::Permissions::empty(); |
57 | |
58 | let mut missing = false; |
59 | for perm in BASE_PERMS { |
60 | if !role.permissions.contains(perm) { |
61 | needed_perms |= perm; |
62 | missing = true; |
63 | } |
64 | } |
65 | |
66 | if missing { |
67 | changes_needed.insert(role.id, needed_perms); |
68 | } |
69 | } |
70 | } |
71 | |
72 | Ok(QuickLockdownTestResult { |
73 | changes_needed, |
74 | critical_roles, |
75 | }) |
76 | } |
77 | |
78 | /// Creates a new quick lockdown given a [PartialGuild](`serenity::all::PartialGuild`) and a set of critical roles |
79 | /// |
80 | /// This is achieved by **removing** the `BASE_PERMS` from the critical roles |
81 | pub async fn create_quick_lockdown( |
82 | ctx: &serenity::client::Context, |
83 | pg: &mut serenity::all::PartialGuild, |
84 | critical_roles: HashSet<serenity::all::RoleId>, |
85 | ) -> Result<(), silverpelt::Error> { |
86 | let mut new_roles = Vec::new(); |
87 | for role in pg.roles.iter() { |
88 | if critical_roles.contains(&role.id) { |
89 | let mut perms = role.permissions; |
90 | |
91 | for perm in BASE_PERMS { |
92 | perms.remove(perm); |
93 | } |
94 | |
95 | new_roles.push( |
96 | pg.id |
97 | .edit_role( |
98 | &ctx.http, |
99 | role.id, |
100 | serenity::all::EditRole::new().permissions(perms), |
101 | ) |
102 | .await?, |
103 | ); |
104 | } |
105 | } |
106 | |
107 | for role in new_roles { |
108 | pg.roles.insert(role); |
109 | } |
110 | |
111 | Ok(()) |
112 | } |
113 | |
114 | /// Reverts a quick lockdown given a [PartialGuild](`serenity::all::PartialGuild`) and a set of critical roles |
115 | /// |
116 | /// This is achieved by **adding** the `BASE_PERMS` to the critical roles |
117 | pub async fn revert_quick_lockdown( |
118 | ctx: &serenity::client::Context, |
119 | pg: &mut serenity::all::PartialGuild, |
120 | critical_roles: HashSet<serenity::all::RoleId>, |
121 | ) -> Result<(), silverpelt::Error> { |
122 | let mut new_roles = Vec::new(); |
123 | for role in pg.roles.iter() { |
124 | if critical_roles.contains(&role.id) { |
125 | let mut perms = role.permissions; |
126 | |
127 | let mut changed = false; |
128 | for perm in BASE_PERMS { |
129 | if !perms.contains(perm) { |
130 | changed = true; |
131 | perms |= perm; |
132 | } |
133 | } |
134 | |
135 | if !changed { |
136 | continue; // Avoid useless API call when no changes are needed |
137 | } |
138 | |
139 | new_roles.push( |
140 | pg.id |
141 | .edit_role( |
142 | &ctx.http, |
143 | role.id, |
144 | serenity::all::EditRole::new().permissions(perms), |
145 | ) |
146 | .await?, |
147 | ); |
148 | } |
149 | } |
150 | |
151 | for role in new_roles { |
152 | pg.roles.insert(role); |
153 | } |
154 | |
155 | Ok(()) |
156 | } |
157 |