3
0
Fork 0
mirror of https://github.com/ZeppelinBot/Zeppelin.git synced 2025-03-16 14:11:50 +00:00

Various fixes

This commit is contained in:
Lily Bergonzat 2024-02-17 18:16:53 +01:00
parent 2c0e4b37ca
commit cafcc2839e
15 changed files with 45 additions and 68 deletions

View file

@ -1,9 +1,8 @@
import { ConfigValidationError, PluginConfigManager } from "knub"; import { BaseConfig, ConfigValidationError, PluginConfigManager } from "knub";
import moment from "moment-timezone";
import { ZodError } from "zod"; import { ZodError } from "zod";
import { ZeppelinPlugin } from "./plugins/ZeppelinPlugin"; import { ZeppelinPlugin } from "./plugins/ZeppelinPlugin";
import { guildPlugins } from "./plugins/availablePlugins"; import { guildPlugins } from "./plugins/availablePlugins";
import { ZeppelinGuildConfig, zZeppelinGuildConfig } from "./types"; import { zZeppelinGuildConfig } from "./types";
import { formatZodIssue } from "./utils/formatZodIssue"; import { formatZodIssue } from "./utils/formatZodIssue";
const pluginNameToPlugin = new Map<string, ZeppelinPlugin>(); const pluginNameToPlugin = new Map<string, ZeppelinPlugin>();
@ -17,14 +16,7 @@ export async function validateGuildConfig(config: any): Promise<string | null> {
return validationResult.error.issues.map(formatZodIssue).join("\n"); return validationResult.error.issues.map(formatZodIssue).join("\n");
} }
const guildConfig = config as ZeppelinGuildConfig; const guildConfig = config as BaseConfig;
if (guildConfig.timezone) {
const validTimezones = moment.tz.names();
if (!validTimezones.includes(guildConfig.timezone)) {
return `Invalid timezone: ${guildConfig.timezone}`;
}
}
if (guildConfig.plugins) { if (guildConfig.plugins) {
for (const [pluginName, pluginOptions] of Object.entries(guildConfig.plugins)) { for (const [pluginName, pluginOptions] of Object.entries(guildConfig.plugins)) {

View file

@ -98,7 +98,7 @@ export const CommonPlugin = zeppelinGuildPlugin<CommonPluginType>()({
body: string, body: string,
allowedMentions?: MessageMentionOptions, allowedMentions?: MessageMentionOptions,
responseInteraction?: ModalSubmitInteraction, responseInteraction?: ModalSubmitInteraction,
ephemeral = false, ephemeral = true,
): Promise<Message | undefined> => { ): Promise<Message | undefined> => {
const emoji = getErrorEmoji(pluginData); const emoji = getErrorEmoji(pluginData);
const formattedBody = errorMessage(body, emoji); const formattedBody = errorMessage(body, emoji);

View file

@ -69,7 +69,6 @@ async function muteAction(
try { try {
const result = await mutes.muteUser(target, durationMs, reason, reason, { caseArgs }); const result = await mutes.muteUser(target, durationMs, reason, reason, { caseArgs });
const messageResultText = result.notifyResult.text ? ` (${result.notifyResult.text})` : ""; const messageResultText = result.notifyResult.text ? ` (${result.notifyResult.text})` : "";
const muteMessage = `Muted **${result.case!.user_name}** ${ const muteMessage = `Muted **${result.case!.user_name}** ${
durationMs ? `for ${humanizeDuration(durationMs)}` : "indefinitely" durationMs ? `for ${humanizeDuration(durationMs)}` : "indefinitely"

View file

@ -32,7 +32,7 @@ export const CasesModMsgCmd = modActionsMsgCmd({
msg, msg,
args.mod, args.mod,
null, null,
msg.author, msg.member,
args.notes, args.notes,
args.warns, args.warns,
args.mutes, args.mutes,

View file

@ -33,7 +33,7 @@ export const CasesSlashCmd = {
interaction, interaction,
options.mod, options.mod,
options.user, options.user,
interaction.user, interaction.member,
options.notes, options.notes,
options.warns, options.warns,
options.mutes, options.mutes,

View file

@ -45,7 +45,7 @@ export const CasesUserMsgCmd = modActionsMsgCmd({
msg, msg,
args.mod, args.mod,
user, user,
msg.author, msg.member,
args.notes, args.notes,
args.warns, args.warns,
args.mutes, args.mutes,

View file

@ -24,7 +24,7 @@ export const WarnMsgCmd = modActionsMsgCmd({
async run({ pluginData, message: msg, args }) { async run({ pluginData, message: msg, args }) {
const user = await resolveUser(pluginData.client, args.user); const user = await resolveUser(pluginData.client, args.user);
if (!user.id) { if (!user.id) {
pluginData.getPlugin(CommonPlugin).sendErrorMessage(msg, `User not found`); await pluginData.getPlugin(CommonPlugin).sendErrorMessage(msg, `User not found`);
return; return;
} }
@ -33,9 +33,9 @@ export const WarnMsgCmd = modActionsMsgCmd({
if (!memberToWarn) { if (!memberToWarn) {
const _isBanned = await isBanned(pluginData, user.id); const _isBanned = await isBanned(pluginData, user.id);
if (_isBanned) { if (_isBanned) {
pluginData.getPlugin(CommonPlugin).sendErrorMessage(msg, `User is banned`); await pluginData.getPlugin(CommonPlugin).sendErrorMessage(msg, `User is banned`);
} else { } else {
pluginData.getPlugin(CommonPlugin).sendErrorMessage(msg, `User not found on the server`); await pluginData.getPlugin(CommonPlugin).sendErrorMessage(msg, `User not found on the server`);
} }
return; return;
@ -43,7 +43,7 @@ export const WarnMsgCmd = modActionsMsgCmd({
// Make sure we're allowed to warn this member // Make sure we're allowed to warn this member
if (!canActOn(pluginData, msg.member, memberToWarn)) { if (!canActOn(pluginData, msg.member, memberToWarn)) {
pluginData.getPlugin(CommonPlugin).sendErrorMessage(msg, "Cannot warn: insufficient permissions"); await pluginData.getPlugin(CommonPlugin).sendErrorMessage(msg, "Cannot warn: insufficient permissions");
return; return;
} }
@ -62,7 +62,7 @@ export const WarnMsgCmd = modActionsMsgCmd({
try { try {
contactMethods = readContactMethodsFromArgs(args); contactMethods = readContactMethodsFromArgs(args);
} catch (e) { } catch (e) {
pluginData.getPlugin(CommonPlugin).sendErrorMessage(msg, e.message); await pluginData.getPlugin(CommonPlugin).sendErrorMessage(msg, e.message);
return; return;
} }

View file

@ -45,7 +45,7 @@ export const WarnSlashCmd = {
const attachments = retrieveMultipleOptions(NUMBER_ATTACHMENTS_CASE_CREATION, options, "attachment"); const attachments = retrieveMultipleOptions(NUMBER_ATTACHMENTS_CASE_CREATION, options, "attachment");
if ((!options.reason || options.reason.trim() === "") && attachments.length < 1) { if ((!options.reason || options.reason.trim() === "") && attachments.length < 1) {
pluginData await pluginData
.getPlugin(CommonPlugin) .getPlugin(CommonPlugin)
.sendErrorMessage(interaction, "Text or attachment required", undefined, undefined, true); .sendErrorMessage(interaction, "Text or attachment required", undefined, undefined, true);
@ -57,9 +57,9 @@ export const WarnSlashCmd = {
if (!memberToWarn) { if (!memberToWarn) {
const _isBanned = await isBanned(pluginData, options.user.id); const _isBanned = await isBanned(pluginData, options.user.id);
if (_isBanned) { if (_isBanned) {
pluginData.getPlugin(CommonPlugin).sendErrorMessage(interaction, `User is banned`); await pluginData.getPlugin(CommonPlugin).sendErrorMessage(interaction, `User is banned`);
} else { } else {
pluginData.getPlugin(CommonPlugin).sendErrorMessage(interaction, `User not found on the server`); await pluginData.getPlugin(CommonPlugin).sendErrorMessage(interaction, `User not found on the server`);
} }
return; return;
@ -67,7 +67,7 @@ export const WarnSlashCmd = {
// Make sure we're allowed to warn this member // Make sure we're allowed to warn this member
if (!canActOn(pluginData, interaction.member, memberToWarn)) { if (!canActOn(pluginData, interaction.member, memberToWarn)) {
pluginData.getPlugin(CommonPlugin).sendErrorMessage(interaction, "Cannot warn: insufficient permissions"); await pluginData.getPlugin(CommonPlugin).sendErrorMessage(interaction, "Cannot warn: insufficient permissions");
return; return;
} }
@ -79,7 +79,7 @@ export const WarnSlashCmd = {
if (options.mod) { if (options.mod) {
if (!canActAsOther) { if (!canActAsOther) {
pluginData await pluginData
.getPlugin(CommonPlugin) .getPlugin(CommonPlugin)
.sendErrorMessage(interaction, "You don't have permission to act as another moderator"); .sendErrorMessage(interaction, "You don't have permission to act as another moderator");
return; return;
@ -92,7 +92,7 @@ export const WarnSlashCmd = {
try { try {
contactMethods = readContactMethodsFromArgs(options) ?? undefined; contactMethods = readContactMethodsFromArgs(options) ?? undefined;
} catch (e) { } catch (e) {
pluginData.getPlugin(CommonPlugin).sendErrorMessage(interaction, e.message); await pluginData.getPlugin(CommonPlugin).sendErrorMessage(interaction, e.message);
return; return;
} }

View file

@ -145,9 +145,9 @@ async function casesModCmd(
expand: boolean | null, expand: boolean | null,
) { ) {
const casesPlugin = pluginData.getPlugin(CasesPlugin); const casesPlugin = pluginData.getPlugin(CasesPlugin);
const caseFilters = { type: In(typesToShow), is_hidden: !!hidden }; const casesFilters = { type: In(typesToShow), is_hidden: !!hidden };
const totalCases = await casesPlugin.getTotalCasesByMod(modId ?? author.id, caseFilters); const totalCases = await casesPlugin.getTotalCasesByMod(modId ?? author.id, casesFilters);
if (totalCases === 0) { if (totalCases === 0) {
pluginData.getPlugin(CommonPlugin).sendErrorMessage(context, `No cases by **${modName}**`); pluginData.getPlugin(CommonPlugin).sendErrorMessage(context, `No cases by **${modName}**`);
@ -159,7 +159,7 @@ async function casesModCmd(
if (expand) { if (expand) {
// Expanded view (= individual case embeds) // Expanded view (= individual case embeds)
const cases = totalCases > 8 ? [] : await casesPlugin.getRecentCasesByMod(modId ?? author.id, 8, 0, caseFilters); const cases = totalCases > 8 ? [] : await casesPlugin.getRecentCasesByMod(modId ?? author.id, 8, 0, casesFilters);
sendExpandedCases(pluginData, context, totalCases, cases); sendExpandedCases(pluginData, context, totalCases, cases);
return; return;
@ -174,7 +174,7 @@ async function casesModCmd(
modId ?? author.id, modId ?? author.id,
casesPerPage, casesPerPage,
(page - 1) * casesPerPage, (page - 1) * casesPerPage,
caseFilters, casesFilters,
); );
const lines = await asyncMap(cases, (c) => casesPlugin.getCaseSummary(c, true, author.id)); const lines = await asyncMap(cases, (c) => casesPlugin.getCaseSummary(c, true, author.id));
@ -212,7 +212,7 @@ export async function actualCasesCmd(
context: Message | ChatInputCommandInteraction, context: Message | ChatInputCommandInteraction,
modId: string | null, modId: string | null,
user: GuildMember | User | UnknownUser | null, user: GuildMember | User | UnknownUser | null,
author: User, author: GuildMember,
notes: boolean | null, notes: boolean | null,
warns: boolean | null, warns: boolean | null,
mutes: boolean | null, mutes: boolean | null,
@ -253,6 +253,6 @@ export async function actualCasesCmd(
} }
user user
? casesUserCmd(pluginData, context, author, modId!, user, modName, typesToShow, hidden, expand) ? casesUserCmd(pluginData, context, author.user, modId!, user, modName, typesToShow, hidden, expand)
: casesModCmd(pluginData, context, author, modId!, mod!, modName, typesToShow, hidden, expand); : casesModCmd(pluginData, context, author.user, modId!, mod ?? author, modName, typesToShow, hidden, expand);
} }

View file

@ -4,6 +4,7 @@ import { waitForReply } from "knub/helpers";
import { CaseTypes } from "../../../../data/CaseTypes"; import { CaseTypes } from "../../../../data/CaseTypes";
import { LogType } from "../../../../data/LogType"; import { LogType } from "../../../../data/LogType";
import { getContextChannel, sendContextResponse } from "../../../../pluginUtils"; import { getContextChannel, sendContextResponse } from "../../../../pluginUtils";
import { MINUTES } from "../../../../utils";
import { CasesPlugin } from "../../../Cases/CasesPlugin"; import { CasesPlugin } from "../../../Cases/CasesPlugin";
import { CommonPlugin } from "../../../Common/CommonPlugin"; import { CommonPlugin } from "../../../Common/CommonPlugin";
import { LogsPlugin } from "../../../Logs/LogsPlugin"; import { LogsPlugin } from "../../../Logs/LogsPlugin";
@ -45,8 +46,8 @@ export async function actualMassUnbanCmd(
// We'll create our own cases below and post a single "mass unbanned" log instead // We'll create our own cases below and post a single "mass unbanned" log instead
userIds.forEach((userId) => { userIds.forEach((userId) => {
// Use longer timeouts since this can take a while // Use longer timeouts since this can take a while
ignoreEvent(pluginData, IgnoredEventType.Unban, userId, 120 * 1000); ignoreEvent(pluginData, IgnoredEventType.Unban, userId, 2 * MINUTES);
pluginData.state.serverLogs.ignoreLog(LogType.MEMBER_UNBAN, userId, 120 * 1000); pluginData.state.serverLogs.ignoreLog(LogType.MEMBER_UNBAN, userId, 2 * MINUTES);
}); });
// Show a loading indicator since this can take a while // Show a loading indicator since this can take a while

View file

@ -37,7 +37,7 @@ export async function actualWarnCmd(
{ confirmText: "Yes", cancelText: "No", restrictToId: authorId }, { confirmText: "Yes", cancelText: "No", restrictToId: authorId },
); );
if (!reply) { if (!reply) {
pluginData.getPlugin(CommonPlugin).sendErrorMessage(context, "Warn cancelled by moderator"); await pluginData.getPlugin(CommonPlugin).sendErrorMessage(context, "Warn cancelled by moderator");
return; return;
} }
} }
@ -53,13 +53,16 @@ export async function actualWarnCmd(
}); });
if (warnResult.status === "failed") { if (warnResult.status === "failed") {
pluginData.getPlugin(CommonPlugin).sendErrorMessage(context, "Failed to warn user"); const failReason = warnResult.error ? `: ${warnResult.error}` : "";
await pluginData.getPlugin(CommonPlugin).sendErrorMessage(context, `Failed to warn user${failReason}`);
return; return;
} }
const messageResultText = warnResult.notifyResult.text ? ` (${warnResult.notifyResult.text})` : ""; const messageResultText = warnResult.notifyResult.text ? ` (${warnResult.notifyResult.text})` : "";
pluginData await pluginData
.getPlugin(CommonPlugin) .getPlugin(CommonPlugin)
.sendSuccessMessage( .sendSuccessMessage(
context, context,

View file

@ -6,6 +6,7 @@ import { CasesPlugin } from "../../Cases/CasesPlugin";
import { CommonPlugin } from "../../Common/CommonPlugin"; import { CommonPlugin } from "../../Common/CommonPlugin";
import { LogsPlugin } from "../../Logs/LogsPlugin"; import { LogsPlugin } from "../../Logs/LogsPlugin";
import { ModActionsPluginType } from "../types"; import { ModActionsPluginType } from "../types";
import { handleAttachmentLinkDetectionAndGetRestriction } from "./attachmentLinkReaction";
import { formatReasonWithMessageLinkForAttachments } from "./formatReasonForAttachments"; import { formatReasonWithMessageLinkForAttachments } from "./formatReasonForAttachments";
export async function updateCase( export async function updateCase(
@ -33,6 +34,10 @@ export async function updateCase(
return; return;
} }
if (await handleAttachmentLinkDetectionAndGetRestriction(pluginData, context, note)) {
return;
}
const formattedNote = await formatReasonWithMessageLinkForAttachments(pluginData, note, context, attachments); const formattedNote = await formatReasonWithMessageLinkForAttachments(pluginData, note, context, attachments);
const casesPlugin = pluginData.getPlugin(CasesPlugin); const casesPlugin = pluginData.getPlugin(CasesPlugin);

View file

@ -1,7 +1,6 @@
import { GuildMember, Snowflake } from "discord.js"; import { GuildMember, Snowflake } from "discord.js";
import { GuildPluginData } from "knub"; import { GuildPluginData } from "knub";
import { CaseTypes } from "../../../data/CaseTypes"; import { CaseTypes } from "../../../data/CaseTypes";
import { getContextChannel, isContextInteraction } from "../../../pluginUtils";
import { TemplateParseError, TemplateSafeValueContainer, renderTemplate } from "../../../templateFormatter"; import { TemplateParseError, TemplateSafeValueContainer, renderTemplate } from "../../../templateFormatter";
import { UserNotificationResult, createUserNotificationError, notifyUser, resolveUser, ucfirst } from "../../../utils"; import { UserNotificationResult, createUserNotificationError, notifyUser, resolveUser, ucfirst } from "../../../utils";
import { userToTemplateSafeUser } from "../../../utils/templateSafeObjects"; import { userToTemplateSafeUser } from "../../../utils/templateSafeObjects";
@ -52,12 +51,7 @@ export async function warnMember(
} }
if (!notifyResult.success) { if (!notifyResult.success) {
const contextIsNotInteraction = if (!warnOptions.retryPromptContext) {
warnOptions.retryPromptContext && !isContextInteraction(warnOptions.retryPromptContext);
const contextChannel = contextIsNotInteraction ? await getContextChannel(warnOptions.retryPromptContext!) : null;
const isValidChannel = contextIsNotInteraction && pluginData.guild.channels.resolve(contextChannel!.id);
if (!warnOptions.retryPromptContext || !isValidChannel) {
return { return {
status: "failed", status: "failed",
error: "Failed to message user", error: "Failed to message user",

View file

@ -1,29 +1,12 @@
import { BaseConfig, Knub } from "knub"; import { Knub } from "knub";
import z from "zod"; import z from "zod";
import { zSnowflake } from "./utils"; import { zSnowflake } from "./utils";
export interface ZeppelinGuildConfig extends BaseConfig {
success_emoji?: string;
error_emoji?: string;
// Deprecated
timezone?: string;
date_formats?: any;
}
export const zZeppelinGuildConfig = z.strictObject({ export const zZeppelinGuildConfig = z.strictObject({
// From BaseConfig // From BaseConfig
prefix: z.string().optional(), prefix: z.string().optional(),
levels: z.record(zSnowflake, z.number()).optional(), levels: z.record(zSnowflake, z.number()).optional(),
plugins: z.record(z.string(), z.unknown()).optional(), plugins: z.record(z.string(), z.unknown()).optional(),
// From ZeppelinGuildConfig
success_emoji: z.string().optional(),
error_emoji: z.string().optional(),
// Deprecated
timezone: z.string().optional(),
date_formats: z.unknown().optional(),
}); });
export type TZeppelinKnub = Knub; export type TZeppelinKnub = Knub;

View file

@ -36,11 +36,11 @@ export async function waitForButtonConfirm(
const sendMethod = () => { const sendMethod = () => {
return contextIsInteraction return contextIsInteraction
? context.replied ? context.replied
? context.followUp ? context.followUp.bind(context)
: context.reply : context.reply.bind(context)
: "send" in context : "send" in context
? context.send ? context.send.bind(context)
: context.channel.send; : context.channel.send.bind(context.channel);
}; };
const extraParameters = contextIsInteraction ? { fetchReply: true } : {}; const extraParameters = contextIsInteraction ? { fetchReply: true } : {};
const message = await sendMethod()({ ...toPost, components: [row], ...extraParameters }); const message = await sendMethod()({ ...toPost, components: [row], ...extraParameters });