rootspring revised this gist . Go to revision
1 file changed, 156 insertions
quick.rs(file created)
@@ -0,0 +1,156 @@ | |||
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 | + | } |
Newer
Older