diff --git a/bots/discord/package.json b/bots/discord/package.json index a6ccb27..d804352 100644 --- a/bots/discord/package.json +++ b/bots/discord/package.json @@ -33,14 +33,14 @@ "@revanced/bot-api": "workspace:*", "@revanced/bot-shared": "workspace:*", "chalk": "^5.3.0", - "decancer": "^3.2.3", + "decancer": "^3.2.4", "discord.js": "^14.15.3", "drizzle-orm": "^0.31.4", "parse-duration": "^1.1.0" }, "devDependencies": { "@libsql/client": "^0.7.0", - "discord-api-types": "^0.37.92", + "discord-api-types": "^0.37.97", "drizzle-kit": "^0.22.8" } } \ No newline at end of file diff --git a/bots/discord/src/database/schemas.ts b/bots/discord/src/database/schemas.ts index e889383..0acee06 100644 --- a/bots/discord/src/database/schemas.ts +++ b/bots/discord/src/database/schemas.ts @@ -16,6 +16,7 @@ export const appliedPresets = sqliteTable( { memberId: text('member').notNull(), guildId: text('guild').notNull(), + removedRoles: text('roles', { mode: 'json' }).notNull().$type().default([]), preset: text('preset').notNull(), until: integer('until'), }, diff --git a/bots/discord/src/events/discord/guildMemberAdd/applyRolePresets.ts b/bots/discord/src/events/discord/guildMemberAdd/applyRolePresets.ts index 90f176f..686350d 100644 --- a/bots/discord/src/events/discord/guildMemberAdd/applyRolePresets.ts +++ b/bots/discord/src/events/discord/guildMemberAdd/applyRolePresets.ts @@ -12,5 +12,5 @@ withContext(on, 'guildMemberAdd', async ({ database }, member) => { ), }) - for (const { preset } of applieds) await applyRolesUsingPreset(preset, member, true) + for (const { preset } of applieds) await applyRolesUsingPreset(preset, member) }) diff --git a/bots/discord/src/utils/discord/rolePresets.ts b/bots/discord/src/utils/discord/rolePresets.ts index 42f1704..4b1ab79 100644 --- a/bots/discord/src/utils/discord/rolePresets.ts +++ b/bots/discord/src/utils/discord/rolePresets.ts @@ -7,7 +7,7 @@ import { and, eq } from 'drizzle-orm' type PresetKey = string export const applyRolePreset = async (member: GuildMember, presetName: PresetKey, expires: number) => { - const afterInsert = await applyRolesUsingPreset(presetName, member, true) + const { removed, callback } = await applyRolesUsingPreset(presetName, member) const until = expires === Infinity ? null : Math.ceil(expires / 1000) await database @@ -16,39 +16,60 @@ export const applyRolePreset = async (member: GuildMember, presetName: PresetKey memberId: member.id, guildId: member.guild.id, preset: presetName, + removedRoles: removed, until, }) .onConflictDoUpdate({ target: [appliedPresets.memberId, appliedPresets.preset, appliedPresets.guildId], set: { until }, }) - .then(afterInsert) + .then(callback) } export const removeRolePreset = async (member: GuildMember, presetName: PresetKey) => { - const afterDelete = await applyRolesUsingPreset(presetName, member, false) + const where = and( + eq(appliedPresets.memberId, member.id), + eq(appliedPresets.preset, presetName), + eq(appliedPresets.guildId, member.guild.id), + ) - await database - .delete(appliedPresets) - .where( - and( - eq(appliedPresets.memberId, member.id), - eq(appliedPresets.preset, presetName), - eq(appliedPresets.guildId, member.guild.id), - ), - ) - .execute() - .then(afterDelete) + const data = await database.query.appliedPresets.findFirst({ where }) + if (!data) return false + + const { callback } = await applyRolesUsingPreset(presetName, member, data.removedRoles) + await database.delete(appliedPresets).where(where).execute().then(callback) + + return true } -export const applyRolesUsingPreset = async (presetName: string, member: GuildMember, applying: boolean) => { +export const applyRolesUsingPreset = async ( + presetName: string, + member: GuildMember, + removePresetGiveRoles?: string[], +) => { const preset = config.rolePresets?.guilds[member.guild.id]?.[presetName] if (!preset) throw new Error(`The preset "${presetName}" does not exist for this server`) const roles = new Set(member.roles.cache.keys()) + const removed: string[] = [] - for (const role of preset.give) roles[applying ? 'add' : 'delete'](role) - for (const role of preset.take) roles[applying ? 'delete' : 'add'](role) + // If removePresetGiveRoles is not provided, we're applying a preset + if (!removePresetGiveRoles) { + for (const role of preset.give) roles.add(role) + for (const role of preset.take) { + if (roles.has(role)) { + roles.delete(role) + removed.push(role) + } + } + } else { + const guildRoles = await member.guild.roles.fetch() + for (const role of preset.give) roles.delete(role) + for (const role of removePresetGiveRoles) if (guildRoles.has(role)) roles.add(role) + } - return () => member.roles.set(Array.from(roles)) + return { + removed, + callback: () => member.roles.set(Array.from(roles)), + } } diff --git a/bun.lockb b/bun.lockb index c8ffb65..d0db354 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/package.json b/package.json index 16ee13c..9febce6 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "@anolilab/multi-semantic-release": "^1.1.3", "@biomejs/biome": "^1.8.3", "@codedependant/semantic-release-docker": "^5.0.3", - "@commitlint/cli": "^19.3.0", + "@commitlint/cli": "^19.4.0", "@commitlint/config-conventional": "^19.2.2", "@saithodev/semantic-release-backmerge": "^4.0.1", "@semantic-release/changelog": "^6.0.3", @@ -41,10 +41,10 @@ "@tsconfig/strictest": "^2.0.5", "@types/bun": "^1.1.6", "conventional-changelog-conventionalcommits": "^7.0.2", - "lefthook": "^1.7.5", + "lefthook": "^1.7.14", "portainer-service-webhook": "https://github.com/newarifrh/portainer-service-webhook#v1", - "semantic-release": "^24.0.0", - "turbo": "^2.0.9", + "semantic-release": "^24.1.0", + "turbo": "^2.0.14", "typescript": "^5.5.4" }, "trustedDependencies": [