-
Notifications
You must be signed in to change notification settings - Fork 59
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
implement mute command #151
Draft
01110111-wave
wants to merge
2
commits into
kaogeek:main
Choose a base branch
from
01110111-wave:mutecommand
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,3 +8,4 @@ services: | |
BOT_TOKEN: dummy | ||
GUILD_ID: dummy | ||
MOD_CHANNEL_ID: dummy | ||
MIC_MUTE_APPEAL_CHANNEL_ID: dummy |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
import { | ||
CacheType, | ||
ChatInputCommandInteraction, | ||
DiscordAPIError, | ||
GuildMember, | ||
} from 'discord.js' | ||
|
||
import { Environment } from '@/config' | ||
import { addUserModerationLogEntry } from '@/features/profileInspector' | ||
import { prisma } from '@/prisma' | ||
import { UserModerationLogEntryType } from '@/types/UserModerationLogEntry' | ||
import { defineCommandHandler } from '@/types/defineCommandHandler' | ||
|
||
export default defineCommandHandler({ | ||
data: { | ||
name: 'appeal-for-server-mute', | ||
description: | ||
'Appeal for microphone muted. Use when server muted only, else you will be timed out for one minute.', | ||
}, | ||
ephemeral: true, | ||
execute: async (_botContext, interaction) => { | ||
if ( | ||
!interaction.isChatInputCommand() || | ||
interaction.channelId !== Environment.MIC_MUTE_APPEAL_CHANNEL_ID | ||
) { | ||
interaction.deleteReply() | ||
return | ||
} | ||
if (interaction.member instanceof GuildMember) { | ||
//when start the bot, all user voice state might be null.This if statement is to prevent it. | ||
if (interaction.member.voice.serverMute === null) { | ||
interaction.editReply('Please join voice channel') | ||
return | ||
} | ||
//prevent spamming appeal when the user is not mute | ||
if (interaction.member.voice.serverMute === false) { | ||
await interaction.editReply( | ||
'You are not muted, you will be timed out for one minute due to the false mute appeal.', | ||
) | ||
try { | ||
//time out does not work on user with higher role hierachy. | ||
await interaction.member.timeout(1000 * 60) | ||
} catch (error) { | ||
if (error instanceof DiscordAPIError && error.code === 50_013) { | ||
console.error(`error`, error.message) | ||
} | ||
} | ||
return | ||
} | ||
//if the user is mute, unmute the user. | ||
//unmuting might be depended on reason why user is server muted. | ||
else { | ||
try { | ||
if (await isMutedForSeverePunishment(interaction)) { | ||
interaction.editReply( | ||
`You were severe muted. Please, appeal to a moderator directly for severe mute pardon.`, | ||
) | ||
} else { | ||
await interaction.member.voice.setMute(false) | ||
await interaction.editReply(`Unmute ${interaction.member.user}`) | ||
await addUserModerationLogEntry( | ||
interaction.user.id, | ||
interaction.user.id, | ||
UserModerationLogEntryType.Mute, | ||
`Unmute ${interaction.member.user.tag} by auto mute appeal`, | ||
) | ||
} | ||
} catch (error) { | ||
if (error instanceof DiscordAPIError && error.code === 40_032) { | ||
interaction.editReply( | ||
`${interaction.member.user}, please connect to voice channel, so we can unmute you.`, | ||
) | ||
} | ||
} | ||
} | ||
} | ||
}, | ||
}) | ||
|
||
async function isMutedForSeverePunishment( | ||
interaction: ChatInputCommandInteraction<CacheType>, | ||
): Promise<boolean> { | ||
const profile = await prisma.userProfile.findFirst({ | ||
where: { id: interaction.user.id }, | ||
}) //retreive the latest mute record of user | ||
//null mean no profile have been registered into DB, so user have not been punished with severe mute. | ||
return profile ? profile.severeMuted : false | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
import { | ||
ApplicationCommandOptionType, | ||
ApplicationCommandType, | ||
CommandInteraction, | ||
DiscordAPIError, | ||
GuildMember, | ||
PermissionsBitField, | ||
} from 'discord.js' | ||
|
||
import { addUserModerationLogEntry } from '@/features/profileInspector' | ||
import { prisma } from '@/prisma' | ||
import { UserModerationLogEntryType } from '@/types/UserModerationLogEntry' | ||
import { defineCommandHandler } from '@/types/defineCommandHandler' | ||
|
||
export default [ | ||
defineCommandHandler({ | ||
data: { | ||
name: 'Severe mute', | ||
type: ApplicationCommandType.User, | ||
defaultMemberPermissions: PermissionsBitField.Flags.MuteMembers, | ||
dmPermission: false, | ||
}, | ||
ephemeral: true, | ||
execute: async (_botContext, interaction) => { | ||
if (!interaction.guild || !interaction.isContextMenuCommand()) return | ||
|
||
const userId = interaction.targetId | ||
const member = interaction.guild.members.cache.get(userId) | ||
if (!member) return | ||
|
||
await severeMute(interaction, member) | ||
}, | ||
}), | ||
defineCommandHandler({ | ||
data: { | ||
name: 'severe-mute', | ||
description: | ||
'Server mute a user, and unallow user to be unmute automatically by mute appeal.', | ||
defaultMemberPermissions: PermissionsBitField.Flags.MuteMembers, | ||
type: ApplicationCommandType.ChatInput, | ||
options: [ | ||
{ | ||
name: 'user', | ||
description: 'The user to mute', | ||
type: ApplicationCommandOptionType.User, | ||
}, | ||
], | ||
}, | ||
ephemeral: true, | ||
execute: async (_botContext, interaction) => { | ||
if (!interaction.guild || !interaction.isChatInputCommand()) return | ||
|
||
const userId = interaction.options.getUser('user')?.id | ||
if (!userId) return | ||
const member = interaction.guild.members.cache.get(userId) | ||
if (!member) return | ||
|
||
await severeMute(interaction, member) | ||
}, | ||
}), | ||
] | ||
async function severeMute( | ||
interaction: CommandInteraction, | ||
member: GuildMember, | ||
) { | ||
try { | ||
//muting might fail if the target is in higher role hierachy. | ||
await member.voice.setMute(true, 'Severe mute from breaking server rules.') // imply that severe mute will be use only when user break server rule. | ||
await prisma.userProfile.upsert({ | ||
where: { id: member.user.id }, | ||
update: { severeMuted: true }, | ||
create: { | ||
id: member.user.id, | ||
tag: member.user.tag, | ||
displayName: member.displayName, | ||
severeMuted: true, | ||
}, | ||
}) // severeMuted bool will be use when mute appeal | ||
await addUserModerationLogEntry( | ||
member.user.id, | ||
interaction.user.id, | ||
UserModerationLogEntryType.Mute, | ||
`Apply severe mute punishment to ${member.user.tag}.`, | ||
) | ||
await interaction.editReply(`${member.user} is severely muted.`) | ||
} catch (error) { | ||
if (error instanceof DiscordAPIError && error.code === 40_032) { | ||
await interaction.editReply( | ||
`${member.user} is not in voice channel, so muting fail.`, | ||
) | ||
} | ||
if (error instanceof DiscordAPIError && error.code === 50_013) { | ||
await interaction.editReply( | ||
`${member.user} is in higher role hierachy than you, so muting fail.`, | ||
) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
import { | ||
ApplicationCommandOptionType, | ||
ApplicationCommandType, | ||
CommandInteraction, | ||
DiscordAPIError, | ||
GuildMember, | ||
PermissionsBitField, | ||
} from 'discord.js' | ||
|
||
import { Environment } from '@/config' | ||
import { addUserModerationLogEntry } from '@/features/profileInspector' | ||
import { prisma } from '@/prisma' | ||
import { UserModerationLogEntryType } from '@/types/UserModerationLogEntry' | ||
import { defineCommandHandler } from '@/types/defineCommandHandler' | ||
|
||
export default [ | ||
defineCommandHandler({ | ||
//please used this command on apology message of punished member, if you deem that they regret their wrong doing. | ||
data: { | ||
name: 'Severe mute pardon', | ||
type: ApplicationCommandType.Message, | ||
defaultMemberPermissions: PermissionsBitField.Flags.MuteMembers, | ||
dmPermission: false, | ||
}, | ||
ephemeral: true, | ||
execute: async (_botContext, interaction) => { | ||
if ( | ||
!interaction.guild || | ||
!interaction.isContextMenuCommand() || | ||
interaction.channelId !== Environment.MIC_MUTE_APPEAL_CHANNEL_ID | ||
) | ||
return | ||
|
||
const messageId = interaction.targetId | ||
const message = await interaction.channel?.messages.fetch(messageId) | ||
if (!message) return | ||
|
||
const userId = message.author.id | ||
const member = interaction.guild.members.cache.get(userId) | ||
if (!member) return | ||
|
||
await severeMutePardon(interaction, member) | ||
}, | ||
}), | ||
defineCommandHandler({ | ||
data: { | ||
name: 'severe-mute-pardon', | ||
description: `Pardon severe mute punishment, this command should not be used unless in case of wrong punishment.`, | ||
type: ApplicationCommandType.ChatInput, | ||
defaultMemberPermissions: PermissionsBitField.Flags.MuteMembers, | ||
options: [ | ||
{ | ||
name: 'user', | ||
description: 'The user to pardon', | ||
type: ApplicationCommandOptionType.User, | ||
}, | ||
], | ||
}, | ||
ephemeral: true, | ||
execute: async (_botContext, interaction) => { | ||
if ( | ||
!interaction.guild || | ||
!interaction.isChatInputCommand() || | ||
interaction.channelId !== Environment.MIC_MUTE_APPEAL_CHANNEL_ID | ||
) | ||
return | ||
|
||
const userId = interaction.options.getUser('user')?.id | ||
if (!userId) return | ||
const member = interaction.guild.members.cache.get(userId) | ||
if (!member) return | ||
|
||
await severeMutePardon(interaction, member) | ||
}, | ||
}), | ||
] | ||
|
||
async function severeMutePardon( | ||
interaction: CommandInteraction, | ||
member: GuildMember, | ||
) { | ||
try { | ||
//unmuting might fail if the target is in higher role hierachy. | ||
await member.voice.setMute(false, 'Pardon severe mute') | ||
await prisma.userProfile.update({ | ||
where: { id: member.user.id }, | ||
data: { severeMuted: false }, | ||
}) | ||
await addUserModerationLogEntry( | ||
member.user.id, | ||
interaction.user.id, | ||
UserModerationLogEntryType.Mute, | ||
`Pardon severe mute punishment to ${member.user.tag}.`, | ||
) | ||
await interaction.editReply( | ||
`${member.user} is pardon for severe mute punishment.`, | ||
) | ||
} catch (error) { | ||
if (error instanceof DiscordAPIError && error.code === 40_032) { | ||
await interaction.editReply( | ||
`${member.user} is not in voice channel, so pardon fail.`, | ||
) | ||
} | ||
if (error instanceof DiscordAPIError && error.code === 50_013) { | ||
await interaction.editReply( | ||
`${member.user} is in higher role hierachy than you, so pardon fail.`, | ||
) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what if user already left the voice channel when a mod decides to severe mute? it won’t crash, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it won't crash the bot.