WIP votekick
This commit is contained in:
parent
e26803a17c
commit
117e3b0f12
6 changed files with 129 additions and 7 deletions
|
@ -87,7 +87,7 @@ export default {
|
|||
await Promise.all([
|
||||
message.reply(`### ${targetName} has been ${Math.random() > 0.8 ? 'ejected' : 'banned'}.\n`
|
||||
+ `Infraction ID: \`${infId}\` (**#${userWarnCount}** for this user)`),
|
||||
logModAction('ban', message.serverContext, message.member!, targetUser._id, reason, infraction, `Ban duration: **Permanent**`),
|
||||
logModAction('ban', message.serverContext, message.member!, targetUser._id, reason, infraction._id, `Ban duration: **Permanent**`),
|
||||
]);
|
||||
} else {
|
||||
let banUntil = Date.now() + banDuration;
|
||||
|
@ -119,7 +119,7 @@ export default {
|
|||
await Promise.all([
|
||||
message.reply(`### ${targetName} has been temporarily banned.\n`
|
||||
+ `Infraction ID: \`${infId}\` (**#${userWarnCount}** for this user)`),
|
||||
logModAction('ban', message.serverContext, message.member!, targetUser._id, reason, infraction, `Ban duration: **${Day(banUntil).fromNow(true)}**`),
|
||||
logModAction('ban', message.serverContext, message.member!, targetUser._id, reason, infraction._id, `Ban duration: **${Day(banUntil).fromNow(true)}**`),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,7 +64,7 @@ export default {
|
|||
await Promise.all([
|
||||
message.reply(`### @${targetUser.username} has been ${Math.random() > 0.8 ? 'yeeted' : 'kicked'}.\n`
|
||||
+ `Infraction ID: \`${infId}\` (**#${userWarnCount}** for this user)`),
|
||||
logModAction('kick', message.serverContext, message.member!, targetUser._id, reason, infraction),
|
||||
logModAction('kick', message.serverContext, message.member!, targetUser._id, reason, infraction._id),
|
||||
]);
|
||||
}
|
||||
} as Command;
|
||||
|
|
116
bot/src/bot/commands/votekick.ts
Normal file
116
bot/src/bot/commands/votekick.ts
Normal file
|
@ -0,0 +1,116 @@
|
|||
import { FindResult } from "monk";
|
||||
import { ulid } from "ulid";
|
||||
import { client } from "../..";
|
||||
import Command from "../../struct/Command";
|
||||
import MessageCommandContext from "../../struct/MessageCommandContext";
|
||||
import ServerConfig from "../../struct/ServerConfig";
|
||||
import { logModAction } from "../modules/mod_logs";
|
||||
import { storeTempBan } from "../modules/tempbans";
|
||||
import { getPermissionLevel, isModerator, parseUser } from "../util";
|
||||
|
||||
type VoteEntry = {
|
||||
id: string;
|
||||
target: string;
|
||||
user: string; // Whoever issued the vote kick
|
||||
server: string;
|
||||
time: number;
|
||||
ignore: boolean;
|
||||
}
|
||||
|
||||
export default {
|
||||
name: 'votekick',
|
||||
aliases: [ 'voteban' ],
|
||||
description: 'Allow trusted users to vote kick users',
|
||||
category: 'moderation',
|
||||
run: async (message: MessageCommandContext, args: string[]) => {
|
||||
try {
|
||||
const serverConfig: ServerConfig = await client.db.get('servers').findOne({ id: message.serverContext._id });
|
||||
if (!serverConfig?.votekick?.enabled) return message.reply('Vote kick is not enabled for this server.');
|
||||
if (!message.member!.roles?.filter(r => serverConfig.votekick?.trustedRoles.includes(r)).length
|
||||
&& !(await isModerator(message))) {
|
||||
return message.reply('🔒 Access denied');
|
||||
}
|
||||
if (args.length == 0) return message.reply(`**Votekick configuration:**\n`
|
||||
+ `Votes required: **${serverConfig.votekick.votesRequired}**\n`
|
||||
+ `Ban duration: **${serverConfig.votekick.banDuration}** (In minutes, -1 = Kick, 0: Permanent)\n`
|
||||
+ `Trusted role IDs: \`${serverConfig.votekick.trustedRoles.join('\`, \`')}\`\n\n`
|
||||
+ `Run \`/votekick [Username, ID or @mention]\` to votekick someone.`);
|
||||
|
||||
const target = await parseUser(args[0]);
|
||||
if (!target) return message.reply('Sorry, I can\'t find this user.');
|
||||
const targetMember = await message.serverContext.fetchMember(target);
|
||||
|
||||
if (await getPermissionLevel(target, message.serverContext) > 0
|
||||
|| targetMember.roles?.filter(r => serverConfig.votekick?.trustedRoles.includes(r)).length) {
|
||||
return message.reply('This target can not be votekicked.');
|
||||
}
|
||||
|
||||
const vote: VoteEntry = {
|
||||
id: ulid(),
|
||||
target: target._id,
|
||||
user: message.author_id,
|
||||
server: message.serverContext._id,
|
||||
time: Date.now(),
|
||||
ignore: false,
|
||||
}
|
||||
|
||||
const votes: FindResult<VoteEntry> = await client.db.get('votekicks').find({
|
||||
server: message.serverContext._id,
|
||||
target: target._id,
|
||||
time: {
|
||||
$gt: Date.now() - 1000 * 60 * 30, // Last 30 minutes
|
||||
},
|
||||
ignore: false,
|
||||
});
|
||||
|
||||
if (votes.find(v => v.user == message.author_id)) return message.reply('You can\'t vote twice for this user.');
|
||||
|
||||
await client.db.get('votekicks').insert(vote);
|
||||
votes.push({ _id: '' as any, ...vote });
|
||||
|
||||
await logModAction(
|
||||
"votekick",
|
||||
message.serverContext,
|
||||
message.member!,
|
||||
target._id,
|
||||
`n/a`,
|
||||
vote.id,
|
||||
`This is vote ${votes.length}/${serverConfig.votekick.votesRequired} for this user.`,
|
||||
);
|
||||
|
||||
if (votes.length >= serverConfig.votekick.votesRequired) {
|
||||
if (serverConfig.votekick.banDuration == -1) {
|
||||
targetMember.kick();
|
||||
} else if (serverConfig.votekick.banDuration == 0) {
|
||||
message.serverContext.banUser(target._id, { reason: 'Automatic permanent ban triggered by /votekick' });
|
||||
} else {
|
||||
message.serverContext.banUser(target._id, { reason: `Automatic temporary ban triggered by /votekick `
|
||||
+ `(${serverConfig.votekick.banDuration} minutes)` });
|
||||
|
||||
await storeTempBan({
|
||||
id: ulid(),
|
||||
bannedUser: target._id,
|
||||
server: message.serverContext._id,
|
||||
until: Date.now() + (1000 * 60 * serverConfig.votekick.banDuration),
|
||||
});
|
||||
}
|
||||
|
||||
message.reply(`**${votes.length}/${serverConfig.votekick.votesRequired}** votes - `
|
||||
+ `Banned @${target.username} for ${serverConfig.votekick.banDuration} minutes.`); // Todo: display ban duration properly (Permban, kick, etc)
|
||||
|
||||
await client.db.get('votekicks').update({
|
||||
server: message.serverContext._id,
|
||||
target: target._id,
|
||||
time: { $gt: Date.now() - 1000 * 60 * 30 },
|
||||
ignore: false,
|
||||
}, { $set: { ignore: true } });
|
||||
} else {
|
||||
message.reply(`Voted to temporarily remove **@${target.username}**. `
|
||||
+ `**${votes.length}/${serverConfig.votekick.votesRequired}** votes.`);
|
||||
}
|
||||
} catch(e) {
|
||||
console.error(e);
|
||||
message.reply('Oops, something happened: ' + e);
|
||||
}
|
||||
}
|
||||
} as Command;
|
|
@ -43,7 +43,7 @@ export default {
|
|||
+ ` for ${await fetchUsername(user._id)}.\n`
|
||||
+ `**Infraction ID:** \`${infraction._id}\`\n`
|
||||
+ `**Reason:** \`${infraction.reason}\``),
|
||||
logModAction('warn', message.serverContext, message.member!, user._id, reason, infraction, `This is warn number ${userWarnCount} for this user.`),
|
||||
logModAction('warn', message.serverContext, message.member!, user._id, reason, infraction._id, `This is warn number ${userWarnCount} for this user.`),
|
||||
]);
|
||||
}
|
||||
} as Command;
|
||||
|
|
|
@ -114,7 +114,7 @@ client.on('packet', async (packet) => {
|
|||
}
|
||||
});
|
||||
|
||||
async function logModAction(type: 'warn'|'kick'|'ban', server: Server, mod: Member, target: string, reason: string|null, infraction: Infraction, extraText?: string): Promise<void> {
|
||||
async function logModAction(type: 'warn'|'kick'|'ban'|'votekick', server: Server, mod: Member, target: string, reason: string|null, infractionID: string, extraText?: string): Promise<void> {
|
||||
try {
|
||||
let config: ServerConfig = await client.db.get('servers').findOne({ id: server._id }) ?? {};
|
||||
|
||||
|
@ -130,7 +130,7 @@ async function logModAction(type: 'warn'|'kick'|'ban', server: Server, mod: Memb
|
|||
description: `\`@${mod.user?.username}\` **${aType}** \``
|
||||
+ `${await fetchUsername(target)}\`${type == 'warn' ? '.' : ` from ${server.name}.`}\n`
|
||||
+ `**Reason**: \`${reason ? reason : 'No reason provided.'}\`\n`
|
||||
+ `**Warn ID**: \`${infraction._id}\`\n`
|
||||
+ `**Warn ID**: \`${infractionID}\`\n`
|
||||
+ (extraText ?? ''),
|
||||
color: embedColor,
|
||||
overrides: {
|
||||
|
@ -138,7 +138,7 @@ async function logModAction(type: 'warn'|'kick'|'ban', server: Server, mod: Memb
|
|||
description: `@${mod.user?.username} ${aType} `
|
||||
+ `${await fetchUsername(target)}${type == 'warn' ? '.' : ` from ${server.name}.`}\n`
|
||||
+ `Reason: ${reason ? reason : 'No reason provided.'}\n`
|
||||
+ `Warn ID: ${infraction._id}\n`
|
||||
+ `Warn ID: ${infractionID}\n`
|
||||
+ (extraText ?? ''),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,12 @@ class ServerConfig {
|
|||
automodSettings: AutomodSettings | undefined;
|
||||
botManagers: string[] | undefined;
|
||||
moderators: string[] | undefined;
|
||||
votekick: {
|
||||
enabled: boolean;
|
||||
votesRequired: number;
|
||||
banDuration: number; // -1: Only kick, 0: Permanent, >0: Ban duration in minutes
|
||||
trustedRoles: string[];
|
||||
} | undefined;
|
||||
linkedServer: string | undefined;
|
||||
whitelist: {
|
||||
users: string[] | undefined,
|
||||
|
|
Loading…
Reference in a new issue