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([
|
await Promise.all([
|
||||||
message.reply(`### ${targetName} has been ${Math.random() > 0.8 ? 'ejected' : 'banned'}.\n`
|
message.reply(`### ${targetName} has been ${Math.random() > 0.8 ? 'ejected' : 'banned'}.\n`
|
||||||
+ `Infraction ID: \`${infId}\` (**#${userWarnCount}** for this user)`),
|
+ `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 {
|
} else {
|
||||||
let banUntil = Date.now() + banDuration;
|
let banUntil = Date.now() + banDuration;
|
||||||
|
@ -119,7 +119,7 @@ export default {
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
message.reply(`### ${targetName} has been temporarily banned.\n`
|
message.reply(`### ${targetName} has been temporarily banned.\n`
|
||||||
+ `Infraction ID: \`${infId}\` (**#${userWarnCount}** for this user)`),
|
+ `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([
|
await Promise.all([
|
||||||
message.reply(`### @${targetUser.username} has been ${Math.random() > 0.8 ? 'yeeted' : 'kicked'}.\n`
|
message.reply(`### @${targetUser.username} has been ${Math.random() > 0.8 ? 'yeeted' : 'kicked'}.\n`
|
||||||
+ `Infraction ID: \`${infId}\` (**#${userWarnCount}** for this user)`),
|
+ `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;
|
} 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`
|
+ ` for ${await fetchUsername(user._id)}.\n`
|
||||||
+ `**Infraction ID:** \`${infraction._id}\`\n`
|
+ `**Infraction ID:** \`${infraction._id}\`\n`
|
||||||
+ `**Reason:** \`${infraction.reason}\``),
|
+ `**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;
|
} 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 {
|
try {
|
||||||
let config: ServerConfig = await client.db.get('servers').findOne({ id: server._id }) ?? {};
|
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}** \``
|
description: `\`@${mod.user?.username}\` **${aType}** \``
|
||||||
+ `${await fetchUsername(target)}\`${type == 'warn' ? '.' : ` from ${server.name}.`}\n`
|
+ `${await fetchUsername(target)}\`${type == 'warn' ? '.' : ` from ${server.name}.`}\n`
|
||||||
+ `**Reason**: \`${reason ? reason : 'No reason provided.'}\`\n`
|
+ `**Reason**: \`${reason ? reason : 'No reason provided.'}\`\n`
|
||||||
+ `**Warn ID**: \`${infraction._id}\`\n`
|
+ `**Warn ID**: \`${infractionID}\`\n`
|
||||||
+ (extraText ?? ''),
|
+ (extraText ?? ''),
|
||||||
color: embedColor,
|
color: embedColor,
|
||||||
overrides: {
|
overrides: {
|
||||||
|
@ -138,7 +138,7 @@ async function logModAction(type: 'warn'|'kick'|'ban', server: Server, mod: Memb
|
||||||
description: `@${mod.user?.username} ${aType} `
|
description: `@${mod.user?.username} ${aType} `
|
||||||
+ `${await fetchUsername(target)}${type == 'warn' ? '.' : ` from ${server.name}.`}\n`
|
+ `${await fetchUsername(target)}${type == 'warn' ? '.' : ` from ${server.name}.`}\n`
|
||||||
+ `Reason: ${reason ? reason : 'No reason provided.'}\n`
|
+ `Reason: ${reason ? reason : 'No reason provided.'}\n`
|
||||||
+ `Warn ID: ${infraction._id}\n`
|
+ `Warn ID: ${infractionID}\n`
|
||||||
+ (extraText ?? ''),
|
+ (extraText ?? ''),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,12 @@ class ServerConfig {
|
||||||
automodSettings: AutomodSettings | undefined;
|
automodSettings: AutomodSettings | undefined;
|
||||||
botManagers: string[] | undefined;
|
botManagers: string[] | undefined;
|
||||||
moderators: 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;
|
linkedServer: string | undefined;
|
||||||
whitelist: {
|
whitelist: {
|
||||||
users: string[] | undefined,
|
users: string[] | undefined,
|
||||||
|
|
Loading…
Reference in a new issue