refactor: remove retroactive autorole functionality and associated database tables
This commit is contained in:
parent
798d3d589c
commit
579e9a8a61
|
|
@ -0,0 +1,11 @@
|
|||
/*
|
||||
Warnings:
|
||||
|
||||
- You are about to drop the `AutoRoleExclude` table. If the table is not empty, all the data it contains will be lost.
|
||||
|
||||
*/
|
||||
-- DropTable
|
||||
DROP TABLE "AutoRoleExclude";
|
||||
|
||||
-- DropEnum
|
||||
DROP TYPE "ExcludeType";
|
||||
|
|
@ -218,20 +218,7 @@ model AutoRoleConfig {
|
|||
updatedAt DateTime @updatedAt
|
||||
}
|
||||
|
||||
model AutoRoleExclude {
|
||||
id String @id @default(uuid())
|
||||
guildId String
|
||||
targetId String // Role ID or User ID
|
||||
type ExcludeType
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@unique([guildId, targetId, type])
|
||||
}
|
||||
|
||||
enum ExcludeType {
|
||||
ROLE
|
||||
USER
|
||||
}
|
||||
|
||||
model RefinementLevelConfig {
|
||||
level Int @id
|
||||
|
|
|
|||
|
|
@ -66,21 +66,9 @@ export async function generateAutoRoleDashboard(guild: import('discord.js').Guil
|
|||
|
||||
const rowBotRole = new ActionRowBuilder<RoleSelectMenuBuilder>().addComponents(botSelect);
|
||||
|
||||
const rowRetroactive = new ActionRowBuilder<ButtonBuilder>().addComponents(
|
||||
new ButtonBuilder()
|
||||
.setCustomId('autorole_retroactive')
|
||||
.setLabel(t(locale, 'commands.autorole.retroactiveBtn'))
|
||||
.setStyle(ButtonStyle.Secondary)
|
||||
.setDisabled(!config?.userRoleIds || config.userRoleIds.length === 0),
|
||||
new ButtonBuilder()
|
||||
.setCustomId('autorole_exclude')
|
||||
.setLabel(t(locale, 'commands.autorole.excludeTitle'))
|
||||
.setStyle(ButtonStyle.Secondary)
|
||||
);
|
||||
|
||||
return {
|
||||
embeds: [embed],
|
||||
components: [rowUserRole, rowBotRole, rowRetroactive]
|
||||
components: [rowUserRole, rowBotRole]
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -150,17 +150,7 @@ export default {
|
|||
// 타임아웃 방지를 위해 즉시 승인
|
||||
await interaction.deferUpdate();
|
||||
|
||||
const guild = interaction.guild!;
|
||||
if (interaction.customId === 'autorole_retroactive') {
|
||||
const config = await autoRoleService.getConfig(guild.id);
|
||||
if (config?.userRoleIds && config.userRoleIds.length > 0) {
|
||||
await autoRoleService.applyRetroactively(guild, config.userRoleIds, interaction.user.id);
|
||||
const { generateAutoRoleDashboard } = require('../commands/autorole');
|
||||
const dashboard = await generateAutoRoleDashboard(guild, locale);
|
||||
await interaction.editReply({ content: t(locale, 'commands.autorole.retroactiveStarted'), ...dashboard });
|
||||
}
|
||||
}
|
||||
// 나머지 버튼 처리
|
||||
// 나머지 버튼 처리 (현재 사용 안함)
|
||||
}, locale);
|
||||
}
|
||||
else if (interaction.isRoleSelectMenu() && interaction.customId.startsWith('autorole_select_')) {
|
||||
|
|
|
|||
|
|
@ -208,12 +208,6 @@ export const en: TranslationSchema = {
|
|||
enabled: 'Enabled',
|
||||
disabled: 'Disabled',
|
||||
updateSuccess: 'Auto role settings have been updated.',
|
||||
retroactiveBtn: 'Apply Retroactively to Entire Server Now',
|
||||
retroactiveConfirm: 'Do you want to scan all server members and assign roles? This may take time depending on the member count.',
|
||||
retroactiveStarted: 'Retroactive assignment has started in the background. Check progress in audit logs.',
|
||||
excludeTitle: 'Retroactive Exclude Settings',
|
||||
excludeDesc: 'Users with specific IDs or roles will be excluded from retroactive assignment.',
|
||||
excludeAddBtn: 'Add Exclude Target',
|
||||
permissionsError: 'Failed to assign role due to low bot hierarchy or missing permissions.',
|
||||
suspendNotice: 'Auto role assignment has been suspended due to insufficient permissions. Please check the bot\'s permissions and role hierarchy.',
|
||||
},
|
||||
|
|
|
|||
|
|
@ -208,12 +208,6 @@ export const ko: TranslationSchema = {
|
|||
enabled: '활성',
|
||||
disabled: '비활성',
|
||||
updateSuccess: '자동 역할 설정이 업데이트되었습니다.',
|
||||
retroactiveBtn: '지금 서버 전체에 소급 적용',
|
||||
retroactiveConfirm: '서버의 모든 멤버를 스캔하여 역할을 부여하시겠습니까? 멤버 수에 따라 시간이 걸릴 수 있습니다.',
|
||||
retroactiveStarted: '백그라운드에서 소급 적용을 시작합니다. 진행 상황은 감사 로그에서 확인하세요.',
|
||||
excludeTitle: '소급 적용 제외 설정',
|
||||
excludeDesc: '특정 ID나 역할을 가진 유저는 소급 적용 대상에서 제외됩니다.',
|
||||
excludeAddBtn: '제외 대상 추가',
|
||||
permissionsError: '봇의 역할 순위가 낮거나 권한이 부족하여 역할을 부여할 수 없습니다.',
|
||||
suspendNotice: '권한 부족으로 인해 자동 역할 부여 기능이 일시 중지되었습니다. 봇의 권한과 역할 순위를 확인해 주세요.',
|
||||
},
|
||||
|
|
|
|||
|
|
@ -162,12 +162,6 @@ export interface TranslationSchema {
|
|||
enabled: string;
|
||||
disabled: string;
|
||||
updateSuccess: string;
|
||||
retroactiveBtn: string;
|
||||
retroactiveConfirm: string;
|
||||
retroactiveStarted: string;
|
||||
excludeTitle: string;
|
||||
excludeDesc: string;
|
||||
excludeAddBtn: string;
|
||||
permissionsError: string;
|
||||
suspendNotice: string;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -38,134 +38,6 @@ export class AutoRoleService {
|
|||
async setEnabled(guildId: string, enabled: boolean) {
|
||||
return this.updateConfig(guildId, { isEnabled: enabled });
|
||||
}
|
||||
|
||||
/**
|
||||
* 소급 적용 제외 대상을 추가합니다.
|
||||
*/
|
||||
async addExclude(guildId: string, targetId: string, type: 'ROLE' | 'USER') {
|
||||
return prisma.autoRoleExclude.upsert({
|
||||
where: {
|
||||
guildId_targetId_type: {
|
||||
guildId,
|
||||
targetId,
|
||||
type,
|
||||
},
|
||||
},
|
||||
create: {
|
||||
guildId,
|
||||
targetId,
|
||||
type,
|
||||
},
|
||||
update: {},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 소급 적용 제외 대상을 제거합니다.
|
||||
*/
|
||||
async removeExclude(guildId: string, targetId: string, type: 'ROLE' | 'USER') {
|
||||
return prisma.autoRoleExclude.deleteMany({
|
||||
where: {
|
||||
guildId,
|
||||
targetId,
|
||||
type,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 소급 적용 제외 대상 목록을 조회합니다.
|
||||
*/
|
||||
async getExcludes(guildId: string) {
|
||||
return prisma.autoRoleExclude.findMany({
|
||||
where: { guildId },
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 특정 멤버가 소급 적용 제외 대상인지 확인합니다.
|
||||
*/
|
||||
async isExcluded(member: GuildMember): Promise<boolean> {
|
||||
const excludes = await this.getExcludes(member.guild.id);
|
||||
|
||||
// 유저 ID 체크
|
||||
if (excludes.some((e: any) => e.type === 'USER' && e.targetId === member.id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 역할 ID 체크
|
||||
if (excludes.some((e: any) => e.type === 'ROLE' && member.roles.cache.has(e.targetId))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 서버 전체에 역할을 소급 적용합니다 (백그라운드 처리).
|
||||
*/
|
||||
async applyRetroactively(guild: Guild, roleIds: string[], initiatorId: string) {
|
||||
if (!roleIds || roleIds.length === 0) return;
|
||||
|
||||
const roles = roleIds.map(id => guild.roles.cache.get(id)).filter((r): r is import('discord.js').Role => r !== undefined);
|
||||
if (roles.length === 0) return;
|
||||
|
||||
// 봇의 권한 및 순위 확인
|
||||
const botMember = guild.members.me;
|
||||
if (!botMember || !botMember.permissions.has(PermissionFlagsBits.ManageRoles)) {
|
||||
logger.warn(`AutoRole: Cannot apply roles in guild ${guild.id} due to missing ManageRoles permission.`);
|
||||
return;
|
||||
}
|
||||
|
||||
const validRoles = roles.filter(r => botMember.roles.highest.position > r.position);
|
||||
if (validRoles.length === 0) {
|
||||
logger.warn(`AutoRole: Cannot apply roles in guild ${guild.id} due to hierarchy limitations.`);
|
||||
return;
|
||||
}
|
||||
|
||||
// 모든 멤버 페치 (캐시되지 않았을 수 있음)
|
||||
const members = await guild.members.fetch();
|
||||
const targets = members.filter(m => !m.user.bot && validRoles.some(r => !m.roles.cache.has(r.id)));
|
||||
|
||||
logger.info(`AutoRole: Starting retroactive application of ${validRoles.length} roles to ${targets.size} members in guild ${guild.id}`);
|
||||
|
||||
let successCount = 0;
|
||||
let failCount = 0;
|
||||
|
||||
// 비동기 실행 (응답 대기 안 함)
|
||||
(async () => {
|
||||
for (const [, member] of targets) {
|
||||
try {
|
||||
if (await this.isExcluded(member)) continue;
|
||||
|
||||
await member.roles.add(validRoles);
|
||||
successCount++;
|
||||
|
||||
// Rate Limit 방지를 위한 지연 (1.5초)
|
||||
await new Promise(resolve => setTimeout(resolve, 1500));
|
||||
} catch (error: any) {
|
||||
if (error.code === 10007 || error.code === 10013) {
|
||||
// Unknown Member / User (이미 나감)
|
||||
continue;
|
||||
}
|
||||
if (error.code === 50013) {
|
||||
// Missing Permissions (도중 권한 상실)
|
||||
logger.error(`AutoRole: Permission lost during retroactive assignment in guild ${guild.id}`);
|
||||
break;
|
||||
}
|
||||
failCount++;
|
||||
logger.error(`AutoRole: Failed to assign role to ${member.user.tag}:`, error);
|
||||
}
|
||||
}
|
||||
|
||||
await auditLogService.log(guild, {
|
||||
category: 'SYSTEM',
|
||||
severity: 'INFO',
|
||||
title: 'Retroactive Role Assignment Completed',
|
||||
description: `Retroactive assignment of roles (${validRoles.map(r => `<@&${r.id}>`).join(', ')}) by <@${initiatorId}> has finished.\n- Success: ${successCount}\n- Failed: ${failCount}`,
|
||||
});
|
||||
})();
|
||||
}
|
||||
}
|
||||
|
||||
export const autoRoleService = new AutoRoleService();
|
||||
|
|
|
|||
Loading…
Reference in New Issue