Skip to content

Commit

Permalink
improvements to /vouches command and activate sticky roles
Browse files Browse the repository at this point in the history
  • Loading branch information
WhatCats committed Jun 24, 2024
1 parent a609c96 commit 29b802a
Show file tree
Hide file tree
Showing 10 changed files with 140 additions and 88 deletions.
11 changes: 4 additions & 7 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,32 +25,29 @@ function requireAll(pattern: string) {
async function main() {
I18n.loadLocales(ASSETS + "lang")

let intents: GatewayIntentBits[]
const intents: GatewayIntentBits[] = []

if (PUBLIC) {
requireAll("modules/exchange/**/*.js")
requireAll("modules/vouch-system/**/*.js")
intents = []
} else {
requireAll("modules/**/*.js")
intents = [
intents.push(
GatewayIntentBits.Guilds,
GatewayIntentBits.DirectMessages,
GatewayIntentBits.GuildMembers,
GatewayIntentBits.GuildMessages,
GatewayIntentBits.MessageContent,
GatewayIntentBits.GuildModeration,
GatewayIntentBits.GuildMessageReactions,
GatewayIntentBits.GuildVoiceStates,
GatewayIntentBits.GuildPresences,
]
)
}

const presence: PresenceData = {
activities: [{ type: ActivityType.Custom, name: process.env.PRESENCE! }],
}

const bot = new ScrimsBot({ hostGuildId: HOST_GUILD_ID, servesHost: true, intents, presence })
const bot = new ScrimsBot({ hostGuildId: HOST_GUILD_ID, intents, presence })
if (TEST) {
console.log(String.raw`Appears to be in order ¯\_(ツ)_/¯`)
process.exit(0)
Expand Down
1 change: 1 addition & 0 deletions src/lib/db/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export * from "./models/PositionRole"
export * from "./models/RejoinRoles"
export * from "./models/Suggestion"
export * from "./models/Ticket"
export * from "./models/TransientRole"
export * from "./models/UserProfile"
export * from "./models/Vouch"
export * from "./util"
Expand Down
19 changes: 19 additions & 0 deletions src/lib/db/models/TransientRole.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { DiscordIdProp, Document, SchemaDocument, getSchemaFromClass, modelSchemaWithCache } from "../util"

@Document("TransientRole", "transientroles")
class TransientRoleSchema {
static isTransient(role: string) {
return cache.has(role)
}

@DiscordIdProp({ required: true })
_id!: string
}

const schema = getSchemaFromClass(TransientRoleSchema)
export const TransientRole = modelSchemaWithCache(schema, TransientRoleSchema)
export type TransientRole = SchemaDocument<typeof schema>

const cache = new Set()
TransientRole.cache.on("add", (role) => cache.add(role._id))
TransientRole.cache.on("delete", (role) => cache.delete(role._id))
4 changes: 4 additions & 0 deletions src/lib/db/models/UserProfile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ class UserProfileSchema {
return UserProfile.cache.get(resolvable) ?? nameCache.get(resolvable.toLowerCase())
}

static getNames() {
return Array.from(nameCache.keys())
}

@DiscordIdProp({ required: true })
_id!: string

Expand Down
9 changes: 7 additions & 2 deletions src/lib/discord/PermissionsManager.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Positions } from "@Constants"
import { Collection, GuildMember, Role, User } from "discord.js"
import { PositionRole, UserProfile, UserRejoinRoles } from "../db"
import { PositionRole, TransientRole, UserProfile, UserRejoinRoles } from "../db"
import type { ScrimsBot } from "./ScrimsBot"

export class PermissionsManager {
Expand Down Expand Up @@ -79,7 +79,12 @@ export class PermissionsManager {
if (!roles.length) return undefined

const member = this.getGuild(guildId)?.members.resolve(user.id)
if (!member) return undefined
if (!member) {
const saved = UserRejoinRoles.cache.get(user.id)
return saved
? roles.some((v) => !TransientRole.isTransient(v) && saved.roles.includes(v))
: undefined
}

// @ts-expect-error the getter on member.roles.cache is very inefficient
return roles.some((v) => member._roles.includes(v))
Expand Down
3 changes: 0 additions & 3 deletions src/lib/discord/ScrimsBot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ export interface BotConfig {
presence?: PresenceData
profiling?: boolean
hostGuildId: string
servesHost?: boolean
}

export function BotListener<E extends keyof ClientEvents>(
Expand All @@ -52,7 +51,6 @@ export class ScrimsBot extends Client {

readonly intents: GatewayIntentBits[]
readonly hostGuildId: string
readonly servesHost: boolean

readonly auditedEvents = new AuditedEventEmitter(this)
readonly partialsHandledEvents = new PartialsHandledEventEmitter(this)
Expand All @@ -76,7 +74,6 @@ export class ScrimsBot extends Client {
super({ partials, intents: config.intents, presence: config.presence })
this.intents = config.intents
this.hostGuildId = config.hostGuildId
this.servesHost = config.servesHost ?? false

this.on("error", console.error)
this.on("shardError", console.error)
Expand Down
10 changes: 5 additions & 5 deletions src/lib/discord/tools/localized-builders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@ declare module "discord.js" {
interface SharedNameAndDescriptionOverwrites {
readonly name: string
readonly description: string
setNameLocalizations: (resourceId: string, ...params: unknown[]) => this
setDescriptionLocalizations: (resourceId: string, ...params: unknown[]) => this
setName: (resourceId: string, ...params: unknown[]) => this
setDescription: (resourceId: string, ...params: unknown[]) => this
setNameAndDescription: (resourceId: string, ...params: unknown[]) => this
setNameLocalizations(resourceId: string, ...params: unknown[]): this
setDescriptionLocalizations(resourceId: string, ...params: unknown[]): this
setName(resourceId: string, ...params: unknown[]): this
setDescription(resourceId: string, ...params: unknown[]): this
setNameAndDescription(resourceId: string, ...params: unknown[]): this
}

const SharedNameAndDescriptionPrototype =
Expand Down
32 changes: 25 additions & 7 deletions src/modules/rank-apps/app-commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,16 @@ SlashCommand({
.setCustomId("users")
.setStyle(TextInputStyle.Paragraph)
.setRequired(true)
.setPlaceholder("Discord ID's joined by line breaks e.g.\n789213718231291\n912360826345382\n...")
.setPlaceholder(
"Discord names or IDs joined by line breaks e.g.\nwhatcats\n977686340412006450\n...",
)

const rank = new TextInputBuilder()
.setLabel("Rank")
.setCustomId("rank")
.setStyle(TextInputStyle.Short)
.setRequired(false)
.setPlaceholder("Pristine, Prime, Private or Premium")

await interaction.showModal(
new ModalBuilder()
Expand All @@ -181,6 +190,7 @@ SlashCommand({
.addComponents(
new ActionRowBuilder<TextInputBuilder>().addComponents(reason),
new ActionRowBuilder<TextInputBuilder>().addComponents(users),
new ActionRowBuilder<TextInputBuilder>().addComponents(rank),
),
)
},
Expand All @@ -191,14 +201,15 @@ SlashCommand({
const components = interaction.components.map((v) => v.components).flat()
const reason = components.find((v) => v.customId === "reason")!.value
const users = components.find((v) => v.customId === "users")!.value.split("\n")
const rank = components.find((v) => v.customId === "rank")?.value.toLowerCase()

const resolved = new Set<UserProfile>()
const problems: string[] = []
const warnings: string[] = []

await Promise.all(
users.map((user) => {
purge(interaction, resolved, user, reason)
purge(interaction, resolved, user, reason, rank)
.then((warning) => {
if (warning) warnings.push(warning)
})
Expand All @@ -221,11 +232,13 @@ SlashCommand({
content += append
}

if (warnings.length) content += `\n### Warnings:`
for (const warning of warnings) {
const append = `\n- ${warning}`
if (append.length + content.length > 2000) break
content += append
if (content.length < 2000) {
if (warnings.length) content += `\n### Warnings:`
for (const warning of warnings) {
const append = `\n- ${warning}`
if (append.length + content.length > 2000) break
content += append
}
}

await interaction.editReply(content)
Expand All @@ -237,6 +250,7 @@ async function purge(
resolved: Set<UserProfile>,
resolvable: string,
reason: string,
rankInput: string | undefined,
): Promise<string | void> {
const user = UserProfile.resolve(resolvable)
if (!user) throw new UserError(`User couldn't be resolved from '${resolvable}'.`)
Expand All @@ -245,6 +259,10 @@ async function purge(
resolved.add(user)

const rank = VouchUtil.determineDemoteRank(user, interaction.user)
if (rankInput && rank.toLowerCase() !== rankInput) {
return `${user} is wrong rank for purge (${rank}).`
}

const removeReason = `Demoted from ${rank} by ${interaction.user.tag}.`
await interaction.client.permissions.removePosition(user, rank, removeReason)

Expand Down
21 changes: 5 additions & 16 deletions src/modules/sticky-roles.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,16 @@
import { Positions } from "@Constants"
import { Events, GuildMember, PartialGuildMember, Role } from "discord.js"
import { BotModule, PositionRole, UserRejoinRoles } from "lib"
import { BotModule, UserRejoinRoles } from "lib"
import { TransientRole } from "../lib/db/models/TransientRole"

class StickyRolesModule extends BotModule {
protected addListeners() {
this.bot.on(Events.GuildMemberRemove, (m) => this.onMemberRemove(m))
// this.bot.on(Events.GuildMemberAdd, (m) => this.onMemberAdd(m))
this.bot.on(Events.GuildMemberAdd, (m) => this.onMemberAdd(m))
}

async onMemberRemove(member: GuildMember | PartialGuildMember) {
if (member.guild.id === this.bot.hostGuildId) {
const roles = member.roles.cache
.filter((r) => !r.managed && r.id !== r.guild.id)
.filter((r) => !this.alwaysIgnoredRoles().includes(r.id))
.map((r) => r.id)
const roles = member.roles.cache.filter((r) => !r.managed && r.id !== r.guild.id).map((r) => r.id)

if (roles.length) {
await UserRejoinRoles.updateOne({ _id: member.id }, { roles }, { upsert: true })
Expand All @@ -31,20 +28,12 @@ class StickyRolesModule extends BotModule {
.filter((r): r is Role => r !== undefined)
.filter((r) => this.bot.hasRolePermissions(r))
.filter((r) => !r.permissions.has("Administrator"))
.filter((r) => !this.currentIgnoredRoles().includes(r.id))
.filter((r) => !TransientRole.isTransient(r.id))
.map((r) => member.roles.add(r)),
)
}
}
}

currentIgnoredRoles() {
return this.alwaysIgnoredRoles()
}

alwaysIgnoredRoles() {
return PositionRole.getPositionRoles(Positions.Member, this.bot.hostGuildId).map((v) => v.roleId)
}
}

export default StickyRolesModule.getInstance()
Loading

0 comments on commit 29b802a

Please sign in to comment.