3
0
Fork 0
mirror of https://github.com/ZeppelinBot/Zeppelin.git synced 2025-07-13 21:57:18 +00:00

Merge branch 'master' into fr_vckick

This commit is contained in:
Miikka 2020-12-12 22:16:40 +02:00 committed by GitHub
commit 93bc15a7de
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 265 additions and 15 deletions

View file

@ -19,7 +19,7 @@ export const BanAction = automodAction({
async apply({ pluginData, contexts, actionConfig, matchResult }) {
const reason = actionConfig.reason || "Kicked automatically";
const contactMethods = resolveActionContactMethods(pluginData, actionConfig);
const contactMethods = actionConfig.notify ? resolveActionContactMethods(pluginData, actionConfig) : undefined;
const deleteMessageDays = actionConfig.deleteMessageDays || undefined;
const caseArgs = {

View file

@ -18,7 +18,7 @@ export const KickAction = automodAction({
async apply({ pluginData, contexts, actionConfig, matchResult }) {
const reason = actionConfig.reason || "Kicked automatically";
const contactMethods = resolveActionContactMethods(pluginData, actionConfig);
const contactMethods = actionConfig.notify ? resolveActionContactMethods(pluginData, actionConfig) : undefined;
const caseArgs = {
modId: pluginData.client.user.id,

View file

@ -31,7 +31,7 @@ export const MuteAction = automodAction({
async apply({ pluginData, contexts, actionConfig, ruleName, matchResult }) {
const duration = actionConfig.duration ? convertDelayStringToMS(actionConfig.duration)! : undefined;
const reason = actionConfig.reason || "Muted automatically";
const contactMethods = resolveActionContactMethods(pluginData, actionConfig);
const contactMethods = actionConfig.notify ? resolveActionContactMethods(pluginData, actionConfig) : undefined;
const caseArgs = {
modId: pluginData.client.user.id,

View file

@ -18,7 +18,7 @@ export const WarnAction = automodAction({
async apply({ pluginData, contexts, actionConfig, matchResult }) {
const reason = actionConfig.reason || "Warned automatically";
const contactMethods = resolveActionContactMethods(pluginData, actionConfig);
const contactMethods = actionConfig.notify ? resolveActionContactMethods(pluginData, actionConfig) : undefined;
const caseArgs = {
modId: pluginData.client.user.id,

View file

@ -0,0 +1,44 @@
import { GuildPluginData } from "knub";
import { CustomEventsPluginType, TCustomEvent } from "../types";
import * as t from "io-ts";
import { convertDelayStringToMS, noop, tDelayString } from "../../../utils";
import { ActionError } from "../ActionError";
export const MakeRoleMentionableAction = t.type({
type: t.literal("make_role_mentionable"),
role: t.string,
timeout: tDelayString,
});
export type TMakeRoleMentionableAction = t.TypeOf<typeof MakeRoleMentionableAction>;
export async function makeRoleMentionableAction(
pluginData: GuildPluginData<CustomEventsPluginType>,
action: TMakeRoleMentionableAction,
values: any,
event: TCustomEvent,
eventData: any,
) {
const role = pluginData.guild.roles.get(action.role);
if (!role) {
throw new ActionError(`Unknown role: ${role}`);
}
await role.edit(
{
mentionable: true,
},
`Custom event: ${event.name}`,
);
const timeout = convertDelayStringToMS(action.timeout)!;
setTimeout(() => {
role
.edit(
{
mentionable: false,
},
`Custom event: ${event.name}`,
)
.catch(noop);
}, timeout);
}

View file

@ -0,0 +1,30 @@
import { GuildPluginData } from "knub";
import { CustomEventsPluginType, TCustomEvent } from "../types";
import * as t from "io-ts";
import { ActionError } from "../ActionError";
export const MakeRoleUnmentionableAction = t.type({
type: t.literal("make_role_unmentionable"),
role: t.string,
});
export type TMakeRoleUnmentionableAction = t.TypeOf<typeof MakeRoleUnmentionableAction>;
export async function makeRoleUnmentionableAction(
pluginData: GuildPluginData<CustomEventsPluginType>,
action: TMakeRoleUnmentionableAction,
values: any,
event: TCustomEvent,
eventData: any,
) {
const role = pluginData.guild.roles.get(action.role);
if (!role) {
throw new ActionError(`Unknown role: ${role}`);
}
await role.edit(
{
mentionable: false,
},
`Custom event: ${event.name}`,
);
}

View file

@ -0,0 +1,41 @@
import { GuildPluginData } from "knub";
import { CustomEventsPluginType, TCustomEvent } from "../types";
import * as t from "io-ts";
import { ActionError } from "../ActionError";
export const SetChannelPermissionOverridesAction = t.type({
type: t.literal("set_channel_permission_overrides"),
channel: t.string,
overrides: t.array(
t.type({
type: t.union([t.literal("member"), t.literal("role")]),
id: t.string,
allow: t.number,
deny: t.number,
}),
),
});
export type TSetChannelPermissionOverridesAction = t.TypeOf<typeof SetChannelPermissionOverridesAction>;
export async function setChannelPermissionOverridesAction(
pluginData: GuildPluginData<CustomEventsPluginType>,
action: TSetChannelPermissionOverridesAction,
values: any,
event: TCustomEvent,
eventData: any,
) {
const channel = pluginData.guild.channels.get(action.channel);
if (!channel) {
throw new ActionError(`Unknown channel: ${action.channel}`);
}
for (const override of action.overrides) {
await channel.editPermission(
override.id,
override.allow,
override.deny,
override.type,
`Custom event: ${event.name}`,
);
}
}

View file

@ -7,6 +7,9 @@ import { addRoleAction } from "../actions/addRoleAction";
import { createCaseAction } from "../actions/createCaseAction";
import { moveToVoiceChannelAction } from "../actions/moveToVoiceChannelAction";
import { messageAction } from "../actions/messageAction";
import { makeRoleMentionableAction } from "../actions/makeRoleMentionableAction";
import { makeRoleUnmentionableAction } from "../actions/makeRoleUnmentionableAction";
import { setChannelPermissionOverridesAction } from "../actions/setChannelPermissionOverrides";
export async function runEvent(
pluginData: GuildPluginData<CustomEventsPluginType>,
@ -24,6 +27,12 @@ export async function runEvent(
await moveToVoiceChannelAction(pluginData, action, values, event, eventData);
} else if (action.type === "message") {
await messageAction(pluginData, action, values);
} else if (action.type === "make_role_mentionable") {
await makeRoleMentionableAction(pluginData, action, values, event, eventData);
} else if (action.type === "make_role_unmentionable") {
await makeRoleUnmentionableAction(pluginData, action, values, event, eventData);
} else if (action.type === "set_channel_permission_overrides") {
await setChannelPermissionOverridesAction(pluginData, action, values, event, eventData);
}
}
} catch (e) {

View file

@ -4,6 +4,9 @@ import { AddRoleAction } from "./actions/addRoleAction";
import { CreateCaseAction } from "./actions/createCaseAction";
import { MoveToVoiceChannelAction } from "./actions/moveToVoiceChannelAction";
import { MessageAction } from "./actions/messageAction";
import { MakeRoleMentionableAction } from "./actions/makeRoleMentionableAction";
import { MakeRoleUnmentionableAction } from "./actions/makeRoleUnmentionableAction";
import { SetChannelPermissionOverridesAction } from "./actions/setChannelPermissionOverrides";
// Triggers
const CommandTrigger = t.type({
@ -17,7 +20,15 @@ type TCommandTrigger = t.TypeOf<typeof CommandTrigger>;
const AnyTrigger = CommandTrigger; // TODO: Make into a union once we have more triggers
type TAnyTrigger = t.TypeOf<typeof AnyTrigger>;
const AnyAction = t.union([AddRoleAction, CreateCaseAction, MoveToVoiceChannelAction, MessageAction]);
const AnyAction = t.union([
AddRoleAction,
CreateCaseAction,
MoveToVoiceChannelAction,
MessageAction,
MakeRoleMentionableAction,
MakeRoleUnmentionableAction,
SetChannelPermissionOverridesAction,
]);
type TAnyAction = t.TypeOf<typeof AnyAction>;
export const CustomEvent = t.type({

View file

@ -8,6 +8,7 @@ import { formatReasonWithAttachments } from "../functions/formatReasonWithAttach
import { banUserId } from "../functions/banUserId";
import { ignoreEvent } from "../functions/ignoreEvent";
import { LogType } from "../../../data/LogType";
import { waitForReaction } from "knub/dist/helpers";
const opts = {
mod: ct.member({ option: true }),
@ -36,19 +37,30 @@ export const BanCmd = modActionsCmd({
const memberToBan = await resolveMember(pluginData.client, pluginData.guild, user.id);
let forceban = false;
if (!memberToBan) {
const banned = await isBanned(pluginData, user.id);
if (banned) {
sendErrorMessage(pluginData, msg.channel, `User is already banned`);
return;
} else {
sendErrorMessage(pluginData, msg.channel, `User not found on the server`);
}
// Ask the mod if we should upgrade to a forceban as the user is not on the server
const notOnServerMsg = await msg.channel.createMessage("User not found on the server, forceban instead?");
const reply = await waitForReaction(pluginData.client, notOnServerMsg, ["✅", "❌"], msg.author.id);
return;
notOnServerMsg.delete();
if (!reply || reply.name === "❌") {
sendErrorMessage(pluginData, msg.channel, "User not on server, ban cancelled by moderator");
return;
} else {
forceban = true;
}
}
}
// Make sure we're allowed to ban this member
if (!canActOn(pluginData, msg.member, memberToBan)) {
// Make sure we're allowed to ban this member if they are on the server
if (!forceban && !canActOn(pluginData, msg.member, memberToBan!)) {
sendErrorMessage(pluginData, msg.channel, "Cannot ban: insufficient permissions");
return;
}
@ -74,7 +86,7 @@ export const BanCmd = modActionsCmd({
const deleteMessageDays = args["delete-days"] ?? pluginData.config.getForMessage(msg).ban_delete_message_days;
const reason = formatReasonWithAttachments(args.reason, msg.attachments);
const banResult = await banUserId(pluginData, memberToBan.id, reason, {
const banResult = await banUserId(pluginData, user.id, reason, {
contactMethods,
caseArgs: {
modId: mod.id,
@ -89,9 +101,14 @@ export const BanCmd = modActionsCmd({
}
// Confirm the action to the moderator
let response = `Banned **${memberToBan.user.username}#${memberToBan.user.discriminator}** (Case #${banResult.case.case_number})`;
let response = "";
if (!forceban) {
response = `Banned **${user.username}#${user.discriminator}** (Case #${banResult.case.case_number})`;
if (banResult.notifyResult.text) response += ` (${banResult.notifyResult.text})`;
} else {
response = `Member forcebanned (Case #${banResult.case.case_number})`;
}
if (banResult.notifyResult.text) response += ` (${banResult.notifyResult.text})`;
sendSuccessMessage(pluginData, msg.channel, response);
},
});

View file

@ -16,7 +16,7 @@ import { NicknameCmd } from "./commands/NicknameCmd";
import { PingCmd } from "./commands/PingCmd";
import { SourceCmd } from "./commands/SourceCmd";
import { ContextCmd } from "./commands/ContextCmd";
import { VcmoveCmd } from "./commands/VcmoveCmd";
import { VcmoveAllCmd, VcmoveCmd } from "./commands/VcmoveCmd";
import { HelpCmd } from "./commands/HelpCmd";
import { AboutCmd } from "./commands/AboutCmd";
import { PluginOptions } from "knub";
@ -124,6 +124,7 @@ export const UtilityPlugin = zeppelinGuildPlugin<UtilityPluginType>()("utility",
ContextCmd,
VcmoveCmd,
VcdisconnectCmd,
VcmoveAllCmd,
HelpCmd,
AboutCmd,
ReloadGuildCmd,

View file

@ -4,11 +4,12 @@ import {
channelMentionRegex,
errorMessage,
isSnowflake,
resolveMember,
simpleClosestStringMatch,
stripObjectToScalars,
} from "../../../utils";
import { sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
import { VoiceChannel } from "eris";
import { Member, VoiceChannel } from "eris";
import { LogType } from "../../../data/LogType";
export const VcmoveCmd = utilityCmd({
@ -93,3 +94,99 @@ export const VcmoveCmd = utilityCmd({
);
},
});
export const VcmoveAllCmd = utilityCmd({
trigger: "vcmoveall",
description: "Move all members of a voice channel to another voice channel",
usage: "!vcmoveall 551767166395875334 767497573560352798",
permission: "can_vcmove",
signature: {
oldChannel: ct.voiceChannel(),
channel: ct.string({ catchAll: true }),
},
async run({ message: msg, args, pluginData }) {
let channel: VoiceChannel;
if (isSnowflake(args.channel)) {
// Snowflake -> resolve channel directly
const potentialChannel = pluginData.guild.channels.get(args.channel);
if (!potentialChannel || !(potentialChannel instanceof VoiceChannel)) {
sendErrorMessage(pluginData, msg.channel, "Unknown or non-voice channel");
return;
}
channel = potentialChannel;
} else if (channelMentionRegex.test(args.channel)) {
// Channel mention -> parse channel id and resolve channel from that
const channelId = args.channel.match(channelMentionRegex)![1];
const potentialChannel = pluginData.guild.channels.get(channelId);
if (!potentialChannel || !(potentialChannel instanceof VoiceChannel)) {
sendErrorMessage(pluginData, msg.channel, "Unknown or non-voice channel");
return;
}
channel = potentialChannel;
} else {
// Search string -> find closest matching voice channel name
const voiceChannels = pluginData.guild.channels.filter(theChannel => {
return theChannel instanceof VoiceChannel;
}) as VoiceChannel[];
const closestMatch = simpleClosestStringMatch(args.channel, voiceChannels, ch => ch.name);
if (!closestMatch) {
sendErrorMessage(pluginData, msg.channel, "No matching voice channels");
return;
}
channel = closestMatch;
}
if (args.oldChannel.voiceMembers.size === 0) {
sendErrorMessage(pluginData, msg.channel, "Voice channel is empty");
return;
}
if (args.oldChannel.id === channel.id) {
sendErrorMessage(pluginData, msg.channel, "Cant move from and to the same channel!");
return;
}
// Cant leave null, otherwise we get an assignment error in the catch
let currMember = msg.member;
const moveAmt = args.oldChannel.voiceMembers.size;
try {
for (const memberWithId of args.oldChannel.voiceMembers) {
currMember = memberWithId[1];
currMember.edit({
channelID: channel.id,
});
pluginData.state.logs.log(LogType.VOICE_CHANNEL_FORCE_MOVE, {
mod: stripObjectToScalars(msg.author),
member: stripObjectToScalars(currMember, ["user", "roles"]),
oldChannel: stripObjectToScalars(args.oldChannel),
newChannel: stripObjectToScalars(channel),
});
}
} catch (e) {
if (msg.member.id === currMember.id) {
sendErrorMessage(pluginData, msg.channel, "Unknown error when trying to move members");
return;
}
sendErrorMessage(
pluginData,
msg.channel,
`Failed to move ${currMember.username}#${currMember.discriminator} (${currMember.id})`,
);
return;
}
sendSuccessMessage(
pluginData,
msg.channel,
`All ${moveAmt} members from **${args.oldChannel.name}** moved to **${channel.name}**`,
);
},
});