Skip to content

Commit 9ae005f

Browse files
Clean up RoleManager (#204)
Cleans up `RoleManager` and replaces a few more hardcoded roles with the following logic: * we do not restore the everyone role * we do not restore any role whose permissions differ from the everyone role (non-vanity roles, roles with elevated permissions, etc.) * we do not restore managed roles (server booster, linked github, bot roles, etc.)
1 parent 51125bc commit 9ae005f

2 files changed

Lines changed: 40 additions & 63 deletions

File tree

src/modules/wheatley/components/role-manager.ts

Lines changed: 34 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ import { set_interval } from "../../../utils/node.js";
1010
import { build_description } from "../../../utils/strings.js";
1111
import { with_retry } from "../../../utils/discord.js";
1212
import { channel_map } from "../../../channel-map.js";
13-
import { role_map } from "../../../role-map.js";
1413
import { wheatley_channels } from "../channels.js";
1514
import { wheatley_roles } from "../roles.js";
15+
import { role_map } from "../../../role-map.js";
1616

1717
export type user_role_entry = {
1818
user_id: string;
@@ -28,38 +28,14 @@ type role_update_listener = {
2828

2929
export default class RoleManager extends BotComponent {
3030
private channels = channel_map(this.wheatley, wheatley_channels.staff_member_log);
31-
private roles = role_map(
32-
this.wheatley,
33-
wheatley_roles.root,
34-
wheatley_roles.moderators,
35-
wheatley_roles.muted,
36-
wheatley_roles.monke,
37-
wheatley_roles.no_off_topic,
38-
wheatley_roles.no_suggestions,
39-
wheatley_roles.no_suggestions_at_all,
40-
wheatley_roles.no_reactions,
41-
wheatley_roles.no_images,
42-
wheatley_roles.no_threads,
43-
wheatley_roles.no_serious_off_topic,
44-
wheatley_roles.no_til,
45-
wheatley_roles.no_memes,
46-
wheatley_roles.voice,
47-
wheatley_roles.featured_bot,
48-
wheatley_roles.official_bot,
49-
wheatley_roles.jedi_council,
50-
wheatley_roles.server_booster,
51-
wheatley_roles.pink,
52-
wheatley_roles.herald,
53-
wheatley_roles.linked_github,
54-
);
31+
32+
private do_not_restore!: Set<string>;
33+
5534
interval: NodeJS.Timeout | null = null;
5635

5736
// current database state
5837
private user_roles = new Map<string, Set<string>>();
5938

60-
// roles that will not be re-applied on join
61-
blacklisted_roles!: Set<string>;
62-
6339
private database = this.wheatley.database.create_proxy<{
6440
user_roles: user_role_entry;
6541
}>();
@@ -77,37 +53,32 @@ export default class RoleManager extends BotComponent {
7753

7854
override async setup(commands: CommandSetBuilder) {
7955
await ensure_index(this.wheatley, this.database.user_roles, { user_id: 1 }, { unique: true });
80-
8156
await this.channels.resolve();
82-
this.roles.resolve();
8357

84-
this.blacklisted_roles = new Set([
85-
// general
86-
this.roles.root.id,
87-
this.roles.moderators.id,
88-
this.wheatley.guild.id, // the everyone id
58+
const roles = role_map(
59+
this.wheatley,
8960
// moderation roles
90-
this.roles.muted.id,
91-
this.roles.monke.id,
92-
this.roles.no_off_topic.id,
93-
this.roles.no_suggestions.id,
94-
this.roles.no_suggestions_at_all.id,
95-
this.roles.no_reactions.id,
96-
this.roles.no_images.id,
97-
this.roles.no_threads.id,
98-
this.roles.no_serious_off_topic.id,
99-
this.roles.no_til.id,
100-
this.roles.no_memes.id,
101-
this.roles.voice.id,
61+
wheatley_roles.muted,
62+
wheatley_roles.monke,
63+
wheatley_roles.no_off_topic,
64+
wheatley_roles.no_suggestions,
65+
wheatley_roles.no_suggestions_at_all,
66+
wheatley_roles.no_reactions,
67+
wheatley_roles.no_images,
68+
wheatley_roles.no_threads,
69+
wheatley_roles.no_serious_off_topic,
70+
wheatley_roles.no_til,
71+
wheatley_roles.no_memes,
72+
wheatley_roles.voice,
10273
// other misc roles
103-
this.roles.featured_bot.id,
104-
this.roles.official_bot.id,
105-
this.roles.jedi_council.id,
106-
this.roles.server_booster.id,
107-
this.roles.pink.id,
108-
this.roles.herald.id,
109-
this.roles.linked_github.id,
110-
]);
74+
wheatley_roles.featured_bot,
75+
wheatley_roles.official_bot,
76+
wheatley_roles.jedi_council,
77+
wheatley_roles.pink,
78+
wheatley_roles.herald,
79+
);
80+
roles.resolve();
81+
this.do_not_restore = new Set([...roles.values()].map(role => role.id));
11182
}
11283

11384
override async on_ready() {
@@ -205,10 +176,15 @@ export default class RoleManager extends BotComponent {
205176
.setTimestamp(Date.now()),
206177
],
207178
});
208-
for (const role of roles_entry.roles) {
209-
if (!this.blacklisted_roles.has(role)) {
210-
await member.roles.add(role);
179+
for (const id of roles_entry.roles) {
180+
if (this.do_not_restore.has(id) || id == this.wheatley.guild.roles.everyone.id) {
181+
continue;
182+
}
183+
const role = this.wheatley.guild.roles.cache.get(id);
184+
if (!role || !role.permissions.equals(this.wheatley.guild.roles.everyone.permissions) || role.managed) {
185+
continue;
211186
}
187+
await member.roles.add(role);
212188
}
213189
}
214190
}

src/role-map.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,7 @@ export function define_roles<const T extends Record<string, { id: string; name?:
1818

1919
type keyed_role_id = named_id & { key: string };
2020

21-
export function role_map<const T extends readonly keyed_role_id[]>(
22-
wheatley: Wheatley,
23-
...role_ids: T
24-
): { resolve(): void } & { [E in T[number] as E["key"]]: Discord.Role } {
21+
export function role_map<const T extends readonly keyed_role_id[]>(wheatley: Wheatley, ...role_ids: T) {
2522
const target: Record<string, unknown> = {};
2623
let resolved = false;
2724
const resolve = () => {
@@ -31,6 +28,7 @@ export function role_map<const T extends readonly keyed_role_id[]>(
3128
}
3229
resolved = true;
3330
};
31+
const values = () => Object.values(target);
3432
return new Proxy(target, {
3533
get(obj, prop) {
3634
if (prop === "resolve") {
@@ -39,7 +37,10 @@ export function role_map<const T extends readonly keyed_role_id[]>(
3937
if (typeof prop === "string") {
4038
assert(resolved, `Role binding accessed before resolution (key: ${prop})`);
4139
}
40+
if (prop === "values") {
41+
return values;
42+
}
4243
return Reflect.get(obj, prop);
4344
},
44-
}) as { resolve(): void } & { [E in T[number] as E["key"]]: Discord.Role };
45+
}) as { resolve(): void; values(): Iterable<Discord.Role> } & { [E in T[number] as E["key"]]: Discord.Role };
4546
}

0 commit comments

Comments
 (0)