3
0
Fork 0
mirror of https://github.com/ZeppelinBot/Zeppelin.git synced 2025-03-15 05:41:51 +00:00

more fixes

Signed-off-by: GitHub <noreply@github.com>
This commit is contained in:
metal 2023-03-11 12:12:48 +00:00 committed by GitHub
parent 343a91e3c3
commit c33a216857
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 81 additions and 58 deletions

View file

@ -56,7 +56,7 @@ export function initDocs(app: express.Express) {
const name = plugin.name;
const info = plugin.info || {};
const commands = (plugin.commands || []).map((cmd) => ({
const commands = (plugin.messageCommands || []).map((cmd) => ({
trigger: cmd.trigger,
permission: cmd.permission,
signature: cmd.signature,

View file

@ -1,5 +1,18 @@
import { GuildChannel, GuildMember, Snowflake, Util, User, GuildTextBasedChannel } from "discord.js";
import { baseCommandParameterTypeHelpers, baseTypeConverters, CommandContext, TypeConversionError } from "knub";
import {
GuildChannel,
GuildMember,
Snowflake,
User,
GuildTextBasedChannel,
escapeCodeBlock,
escapeInlineCode,
} from "discord.js";
import {
baseCommandParameterTypeHelpers,
messageCommandBaseTypeConverters,
CommandContext,
TypeConversionError,
} from "knub";
import { createTypeHelper } from "knub-command-manager";
import {
channelMentionRegex,
@ -14,11 +27,9 @@ import {
import { isValidTimezone } from "./utils/isValidTimezone";
import { MessageTarget, resolveMessageTarget } from "./utils/resolveMessageTarget";
import { inputPatternToRegExp } from "./validatorUtils";
import { getChannelId } from "knub/dist/utils";
import { disableCodeBlocks } from "knub/dist/helpers";
export const commandTypes = {
...baseTypeConverters,
...messageCommandBaseTypeConverters,
delay(value) {
const result = convertDelayStringToMS(value);
@ -32,7 +43,7 @@ export const commandTypes = {
async resolvedUser(value, context: CommandContext<any>) {
const result = await resolveUser(context.pluginData.client, value);
if (result == null || result instanceof UnknownUser) {
throw new TypeConversionError(`User \`${Util.escapeCodeBlock(value)}\` was not found`);
throw new TypeConversionError(`User \`${escapeCodeBlock(value)}\` was not found`);
}
return result;
},
@ -40,7 +51,7 @@ export const commandTypes = {
async resolvedUserLoose(value, context: CommandContext<any>) {
const result = await resolveUser(context.pluginData.client, value);
if (result == null) {
throw new TypeConversionError(`Invalid user: \`${Util.escapeCodeBlock(value)}\``);
throw new TypeConversionError(`Invalid user: \`${escapeCodeBlock(value)}\``);
}
return result;
},
@ -52,9 +63,7 @@ export const commandTypes = {
const result = await resolveMember(context.pluginData.client, context.message.channel.guild, value);
if (result == null) {
throw new TypeConversionError(
`Member \`${Util.escapeCodeBlock(value)}\` was not found or they have left the server`,
);
throw new TypeConversionError(`Member \`${escapeCodeBlock(value)}\` was not found or they have left the server`);
}
return result;
},
@ -64,7 +73,7 @@ export const commandTypes = {
const result = await resolveMessageTarget(context.pluginData, value);
if (!result) {
throw new TypeConversionError(`Unknown message \`${Util.escapeInlineCode(value)}\``);
throw new TypeConversionError(`Unknown message \`${escapeInlineCode(value)}\``);
}
return result;
@ -84,20 +93,20 @@ export const commandTypes = {
return value as Snowflake;
}
throw new TypeConversionError(`Could not parse ID: \`${Util.escapeInlineCode(value)}\``);
throw new TypeConversionError(`Could not parse ID: \`${escapeInlineCode(value)}\``);
},
regex(value: string, context: CommandContext<any>): RegExp {
try {
return inputPatternToRegExp(value);
} catch (e) {
throw new TypeConversionError(`Could not parse RegExp: \`${Util.escapeInlineCode(e.message)}\``);
throw new TypeConversionError(`Could not parse RegExp: \`${escapeInlineCode(e.message)}\``);
}
},
timezone(value: string) {
if (!isValidTimezone(value)) {
throw new TypeConversionError(`Invalid timezone: ${Util.escapeInlineCode(value)}`);
throw new TypeConversionError(`Invalid timezone: ${escapeInlineCode(value)}`);
}
return value;
@ -105,7 +114,7 @@ export const commandTypes = {
guildTextBasedChannel(value: string, context: CommandContext<any>) {
// FIXME: Remove once Knub's types have been fixed
return baseTypeConverters.textChannel(value, context) as GuildTextBasedChannel;
return messageCommandBaseTypeConverters.textChannel(value, context) as GuildTextBasedChannel;
},
};

View file

@ -53,13 +53,13 @@ export class GuildSavedMessages extends BaseGuildRepository<SavedMessage> {
title: embed.title,
description: embed.description,
url: embed.url,
timestamp: embed.timestamp,
timestamp: embed.timestamp ? Date.parse(embed.timestamp) : null,
color: embed.color,
fields: embed.fields.map((field) => ({
name: field.name,
value: field.value,
inline: field.inline,
inline: field.inline ?? false,
})),
author: embed.author

View file

@ -1,4 +1,4 @@
import { Snowflake } from "discord.js";
import { Snowflake, StickerFormatType, StickerType } from "discord.js";
import { Column, Entity, PrimaryColumn } from "typeorm";
export interface ISavedMessageAttachmentData {
@ -55,13 +55,13 @@ export interface ISavedMessageEmbedData {
}
export interface ISavedMessageStickerData {
format: string;
format: StickerFormatType;
guildId: Snowflake | null;
id: Snowflake;
name: string;
description: string | null;
available: boolean | null;
type: string | null;
type: StickerType | null;
}
export interface ISavedMessageData {

View file

@ -38,7 +38,7 @@ export const AlertAction = automodAction({
const channel = pluginData.guild.channels.cache.get(actionConfig.channel as Snowflake);
const logs = pluginData.getPlugin(LogsPlugin);
if (channel?.isText()) {
if (channel?.isTextBased()) {
const text = actionConfig.text;
const theMessageLink =
contexts[0].message && messageLink(pluginData.guild.id, contexts[0].message.channel_id, contexts[0].message.id);

View file

@ -36,7 +36,7 @@ export const ReplyAction = automodAction({
.filter((c) => c.message?.channel_id)
.filter((c) => {
const channel = pluginData.guild.channels.cache.get(c.message!.channel_id as Snowflake);
return channel?.isText();
return channel?.isTextBased();
});
const contextsByChannelId = contextsWithTextChannels.reduce((map: Map<string, AutomodContext[]>, context) => {

View file

@ -32,7 +32,7 @@ export const StartThreadAction = automodAction({
const threads = contexts.filter((c) => {
if (!c.message || !c.user) return false;
const channel = pluginData.guild.channels.cache.get(c.message.channel_id);
if (channel?.type !== ChannelTypeStrings.TEXT || !channel.isText()) return false; // for some reason the typing here for channel.type defaults to ThreadChannelTypes (?)
if (channel?.type !== ChannelTypeStrings.TEXT || !channel.isTextBased()) return false; // for some reason the typing here for channel.type defaults to ThreadChannelTypes (?)
// check against max threads per channel
if (actionConfig.limit_per_channel && actionConfig.limit_per_channel > 0) {
const threadCount = channel.threads.cache.filter(

View file

@ -19,7 +19,7 @@ export function resolveActionContactMethods(
}
const channel = pluginData.guild.channels.cache.get(actionConfig.notifyChannel as Snowflake);
if (!channel?.isText()) {
if (!channel?.isTextBased()) {
throw new RecoverablePluginError(ERRORS.INVALID_USER_NOTIFICATION_CHANNEL);
}

View file

@ -68,7 +68,7 @@ export const ViewCounterCmd = guildPluginMessageCommand<CountersPluginType>()({
}
const potentialChannel = pluginData.guild.channels.resolve(reply.content as Snowflake);
if (!potentialChannel?.isText()) {
if (!potentialChannel?.isTextBased()) {
sendErrorMessage(pluginData, message.channel, "Channel is not a text channel, cancelling");
return;
}

View file

@ -88,7 +88,7 @@ export async function log<TLogType extends keyof ILogTypeData>(
logChannelLoop: for (const [channelId, opts] of Object.entries(logChannels)) {
const channel = pluginData.guild.channels.cache.get(channelId as Snowflake);
if (!channel?.isText()) continue;
if (!channel?.isTextBased()) continue;
if (pluginData.state.channelCooldowns.isOnCooldown(channelId)) continue;
if (opts.include?.length && !opts.include.includes(typeStr)) continue;
if (opts.exclude && opts.exclude.includes(typeStr)) continue;

View file

@ -186,7 +186,7 @@ export async function muteUser(
const channel = config.message_channel
? pluginData.guild.channels.cache.get(config.message_channel as Snowflake)
: null;
if (useChannel && channel?.isText()) {
if (useChannel && channel?.isTextBased()) {
contactMethods.push({ type: "channel", channel });
}
}

View file

@ -30,7 +30,7 @@ export async function actualPostCmd(
"repeat-times"?: number;
} = {},
) {
if (!targetChannel.isText()) {
if (!targetChannel.isTextBased()) {
msg.channel.send(errorMessage("Specified channel is not a text-based channel"));
return;
}

View file

@ -45,7 +45,7 @@ export async function postScheduledPost(pluginData: GuildPluginData<PostPluginTy
// Post the message
const channel = pluginData.guild.channels.cache.get(post.channel_id as Snowflake);
if (channel?.isText() || channel?.isThread()) {
if (channel?.isTextBased() || channel?.isThread()) {
const [username, discriminator] = post.author_name.split("#");
const author: User = (await pluginData.client.users.fetch(post.author_id as Snowflake)) || {
id: post.author_id,

View file

@ -9,7 +9,7 @@ import humanizeDuration from "humanize-duration";
export async function postReminder(pluginData: GuildPluginData<RemindersPluginType>, reminder: Reminder) {
const channel = pluginData.guild.channels.cache.get(reminder.channel_id as Snowflake);
if (channel && (channel.isText() || channel.isThread())) {
if (channel && (channel.isTextBased() || channel.isThread())) {
try {
// Only show created at date if one exists
if (moment.utc(reminder.created_at).isValid()) {

View file

@ -19,7 +19,7 @@ export async function applyRoleButtons(
// Remove existing role buttons, if any
if (existingSavedButtons?.channel_id) {
const existingChannel = await pluginData.guild.channels.fetch(configItem.message.channel_id).catch(() => null);
const existingMessage = await (existingChannel?.isText() &&
const existingMessage = await (existingChannel?.isTextBased() &&
existingChannel.messages.fetch(existingSavedButtons.message_id).catch(() => null));
if (existingMessage && existingMessage.components.length) {
await existingMessage.edit({
@ -32,7 +32,7 @@ export async function applyRoleButtons(
if ("message_id" in configItem.message) {
// channel id + message id: apply role buttons to existing message
const channel = await pluginData.guild.channels.fetch(configItem.message.channel_id).catch(() => null);
const messageCandidate = await (channel?.isText() &&
const messageCandidate = await (channel?.isTextBased() &&
channel.messages.fetch(configItem.message.message_id).catch(() => null));
if (!messageCandidate) {
pluginData.getPlugin(LogsPlugin).logBotAlert({
@ -55,10 +55,10 @@ export async function applyRoleButtons(
}
const channel = await pluginData.guild.channels.fetch(configItem.message.channel_id).catch(() => null);
if (channel && (!channel.isText || typeof channel.isText !== "function")) {
if (channel && (!channel.isTextBased || typeof channel.isTextBased !== "function")) {
console.log("wtf", pluginData.guild?.id, configItem.message.channel_id);
}
if (!channel || !channel?.isText?.()) {
if (!channel || !channel?.isTextBased()) {
pluginData.getPlugin(LogsPlugin).logBotAlert({
body: `Text channel not found for role_buttons/${configItem.name}`,
});

View file

@ -1,3 +1,4 @@
import { ChannelType } from "discord.js";
import { GuildPluginData } from "knub";
import { StarboardMessage } from "../../../data/entities/StarboardMessage";
import { noop } from "../../../utils";
@ -12,7 +13,7 @@ export async function removeMessageFromStarboard(
// this code is now Almeida-certified and no longer ugly :ok_hand: :cake:
const channel = pluginData.client.channels.cache.find((c) => c.id === msg.starboard_channel_id);
if (!channel?.isText()) return;
if (channel?.type !== ChannelType.GuildText) return;
const message = await channel.messages.fetch(msg.starboard_message_id).catch(noop);
if (!message?.deletable) return;
await message.delete().catch(noop);

View file

@ -81,7 +81,7 @@ export async function cleanCmd(pluginData: GuildPluginData<UtilityPluginType>, a
}
const targetChannel = args.channel ? pluginData.guild.channels.cache.get(args.channel as Snowflake) : msg.channel;
if (!targetChannel?.isText()) {
if (!targetChannel?.isTextBased()) {
sendErrorMessage(pluginData, msg.channel, `Invalid channel specified`);
return;
}

View file

@ -1,4 +1,4 @@
import { MessageEmbedOptions, Role } from "discord.js";
import { MessageEmbedOptions } from "discord.js";
import humanizeDuration from "humanize-duration";
import { GuildPluginData } from "knub";
import moment from "moment-timezone";

View file

@ -1,7 +1,7 @@
import * as t from "io-ts";
import { BaseConfig, Knub } from "knub";
export interface ZeppelinGuildConfig extends BaseConfig<any> {
export interface ZeppelinGuildConfig extends BaseConfig {
success_emoji?: string;
error_emoji?: string;
@ -26,7 +26,7 @@ export const ZeppelinGuildConfigSchema = t.type({
});
export const PartialZeppelinGuildConfigSchema = t.partial(ZeppelinGuildConfigSchema.props);
export interface ZeppelinGlobalConfig extends BaseConfig<any> {
export interface ZeppelinGlobalConfig extends BaseConfig {
url: string;
owners?: string[];
}
@ -37,7 +37,7 @@ export const ZeppelinGlobalConfigSchema = t.type({
plugins: t.record(t.string, t.unknown),
});
export type TZeppelinKnub = Knub<ZeppelinGuildConfig, ZeppelinGlobalConfig>;
export type TZeppelinKnub = Knub;
/**
* Wrapper for the string type that indicates the text will be parsed as Markdown later

View file

@ -1,10 +1,10 @@
import { Channel, ThreadChannel } from "discord.js";
import { AnyThreadChannel, Channel, ChannelType } from "discord.js";
import { ChannelTypeStrings } from "src/types";
export function isThreadChannel(channel: Channel): channel is ThreadChannel {
export function isThreadChannel(channel: Channel): channel is AnyThreadChannel {
return (
channel.type === ChannelTypeStrings.NEWS_THREAD ||
channel.type === ChannelTypeStrings.PUBLIC_THREAD ||
channel.type === ChannelTypeStrings.PRIVATE_THREAD
channel.type === ChannelType.PublicThread ||
channel.type === ChannelType.PrivateThread ||
channel.type === ChannelType.AnnouncementThread
);
}

View file

@ -47,7 +47,7 @@ export async function resolveMessageTarget(pluginData: GuildPluginData<any>, val
}
const channel = pluginData.guild.channels.resolve(result.channelId as Snowflake);
if (!channel?.isText()) {
if (!channel?.isTextBased()) {
return null;
}

View file

@ -9,6 +9,7 @@ import {
Snowflake,
StageInstance,
Sticker,
StickerFormatType,
ThreadChannel,
User,
} from "discord.js";
@ -239,7 +240,7 @@ export function userToTemplateSafeUser(user: User | UnknownUser): TemplateSafeUs
discriminator: user.discriminator,
mention: `<@${user.id}>`,
tag: user.tag,
avatarURL: user.displayAvatarURL?.({ dynamic: true }),
avatarURL: user.displayAvatarURL?.(),
bot: user.bot,
createdAt: user.createdTimestamp,
});
@ -305,9 +306,9 @@ export function stickerToTemplateSafeSticker(sticker: Sticker): TemplateSafeStic
packId: sticker.packId ?? undefined,
name: sticker.name,
description: sticker.description ?? "",
tags: sticker.tags?.join(", ") ?? "",
tags: sticker.tags ?? "",
format: sticker.format,
animated: sticker.format === "PNG" ? false : true,
animated: sticker.format === StickerFormatType.PNG ? false : true,
url: sticker.url,
});
}

View file

@ -1,23 +1,35 @@
import { MessageActionRow, MessageButton, MessageComponentInteraction, MessageOptions, TextChannel } from "discord.js";
import {
ActionRow,
ActionRowBuilder,
ButtonBuilder,
ButtonComponent,
ButtonStyle,
Message,
MessageActionRowComponentBuilder,
MessageComponentInteraction,
MessageCreateOptions,
MessagePayloadOption,
TextChannel,
} from "discord.js";
import { noop } from "knub/dist/utils";
import moment from "moment";
import uuidv4 from "uuid/v4";
export async function waitForButtonConfirm(
channel: TextChannel,
toPost: MessageOptions,
toPost: MessageCreateOptions,
options?: WaitForOptions,
): Promise<boolean> {
return new Promise(async (resolve) => {
const idMod = `${channel.guild.id}-${moment.utc().valueOf()}`;
const row = new MessageActionRow().addComponents([
new MessageButton()
.setStyle("SUCCESS")
const row = new ActionRowBuilder<MessageActionRowComponentBuilder>().addComponents([
new ButtonBuilder()
.setStyle(ButtonStyle.Success)
.setLabel(options?.confirmText || "Confirm")
.setCustomId(`confirmButton:${idMod}:${uuidv4()}`),
new MessageButton()
.setStyle("DANGER")
new ButtonBuilder()
.setStyle(ButtonStyle.Danger)
.setLabel(options?.cancelText || "Cancel")
.setCustomId(`cancelButton:${idMod}:${uuidv4()}`),
]);
@ -41,7 +53,7 @@ export async function waitForButtonConfirm(
}
});
collector.on("end", () => {
if (!message.deleted) message.delete().catch(noop);
if (message.deletable) message.delete().catch(noop);
resolve(false);
});
});