Update djs & knub (#395)
* update pkgs Signed-off-by: GitHub <noreply@github.com> * new knub typings Signed-off-by: GitHub <noreply@github.com> * more pkg updates Signed-off-by: GitHub <noreply@github.com> * more fixes Signed-off-by: GitHub <noreply@github.com> * channel typings Signed-off-by: GitHub <noreply@github.com> * more message utils typings fixes Signed-off-by: GitHub <noreply@github.com> * migrate permissions Signed-off-by: GitHub <noreply@github.com> * fix: InternalPoster webhookables Signed-off-by: GitHub <noreply@github.com> * djs typings: Attachment & Util Signed-off-by: GitHub <noreply@github.com> * more typings Signed-off-by: GitHub <noreply@github.com> * fix: rename permissionNames Signed-off-by: GitHub <noreply@github.com> * more fixes Signed-off-by: GitHub <noreply@github.com> * half the number of errors * knub commands => messageCommands Signed-off-by: GitHub <noreply@github.com> * configPreprocessor => configParser Signed-off-by: GitHub <noreply@github.com> * fix channel.messages Signed-off-by: GitHub <noreply@github.com> * revert automod any typing Signed-off-by: GitHub <noreply@github.com> * more configParser typings Signed-off-by: GitHub <noreply@github.com> * revert Signed-off-by: GitHub <noreply@github.com> * remove knub type params Signed-off-by: GitHub <noreply@github.com> * fix more MessageEmbed / MessageOptions Signed-off-by: GitHub <noreply@github.com> * dumb commit for @almeidx to see why this is stupid Signed-off-by: GitHub <noreply@github.com> * temp disable custom_events Signed-off-by: GitHub <noreply@github.com> * more minor typings fixes - 23 err left Signed-off-by: GitHub <noreply@github.com> * update djs dep * +debug build method (revert this) Signed-off-by: GitHub <noreply@github.com> * Revert "+debug build method (revert this)" This reverts commit a80af1e729b742d1aad1097df538d224fbd32ce7. * Redo +debug build (Revert this) Signed-off-by: GitHub <noreply@github.com> * uniform before/after Load shorthands Signed-off-by: GitHub <noreply@github.com> * remove unused imports & add prettier plugin Signed-off-by: GitHub <noreply@github.com> * env fixes for web platform hosting Signed-off-by: GitHub <noreply@github.com> * feat: knub v32-next; related fixes * fix: allow legacy keys in change_perms action * fix: request Message Content intent * fix: use Knub's config validation logic in API * fix(dashboard): fix error when there are no message and/or slash commands in a plugin * fix(automod): start_thread action thread options * fix(CustomEvents): message command types * chore: remove unneeded type annotation * feat: add forum channel icon; use thread icon for news threads * chore: make tslint happy * chore: fix formatting --------- Signed-off-by: GitHub <noreply@github.com> Co-authored-by: almeidx <almeidx@pm.me> Co-authored-by: Dragory <2606411+Dragory@users.noreply.github.com>
This commit is contained in:
parent
293115af22
commit
06877e90cc
476 changed files with 2965 additions and 3251 deletions
|
@ -2,19 +2,23 @@
|
|||
* @file Utility functions that are plugin-instance-specific (i.e. use PluginData)
|
||||
*/
|
||||
|
||||
import { GuildMember, Message, MessageMentionOptions, MessageOptions, TextChannel } from "discord.js";
|
||||
import { GuildMember, Message, MessageCreateOptions, MessageMentionOptions, TextBasedChannel } from "discord.js";
|
||||
import * as t from "io-ts";
|
||||
import { CommandContext, configUtils, ConfigValidationError, GuildPluginData, helpers, PluginOptions } from "knub";
|
||||
import { PluginOverrideCriteria } from "knub/dist/config/configTypes";
|
||||
import { ExtendedMatchParams } from "knub/dist/config/PluginConfigManager"; // TODO: Export from Knub index
|
||||
import { AnyPluginData } from "knub/dist/plugins/PluginData";
|
||||
import {
|
||||
AnyPluginData,
|
||||
CommandContext,
|
||||
ConfigValidationError,
|
||||
ExtendedMatchParams,
|
||||
GuildPluginData,
|
||||
helpers,
|
||||
PluginOverrideCriteria,
|
||||
} from "knub";
|
||||
import { logger } from "./logger";
|
||||
import { ZeppelinPlugin } from "./plugins/ZeppelinPlugin";
|
||||
import { TZeppelinKnub } from "./types";
|
||||
import { deepKeyIntersect, errorMessage, successMessage, tDeepPartial, tNullable } from "./utils";
|
||||
import { Tail } from "./utils/typeUtils";
|
||||
import { decodeAndValidateStrict, StrictValidationError, validate } from "./validatorUtils";
|
||||
import { isStaff } from "./staff";
|
||||
import { TZeppelinKnub } from "./types";
|
||||
import { errorMessage, successMessage, tNullable } from "./utils";
|
||||
import { Tail } from "./utils/typeUtils";
|
||||
import { StrictValidationError, validate } from "./validatorUtils";
|
||||
|
||||
const { getMemberLevel } = helpers;
|
||||
|
||||
|
@ -91,117 +95,32 @@ export function strictValidationErrorToConfigValidationError(err: StrictValidati
|
|||
);
|
||||
}
|
||||
|
||||
export function getPluginConfigPreprocessor(
|
||||
blueprint: ZeppelinPlugin,
|
||||
customPreprocessor?: ZeppelinPlugin["configPreprocessor"],
|
||||
) {
|
||||
return async (options: PluginOptions<any>, strict?: boolean) => {
|
||||
// 1. Validate the basic structure of plugin config
|
||||
const basicOptionsValidation = validate(BasicPluginStructureType, options);
|
||||
if (basicOptionsValidation instanceof StrictValidationError) {
|
||||
throw strictValidationErrorToConfigValidationError(basicOptionsValidation);
|
||||
export function makeIoTsConfigParser<Schema extends t.Type<any>>(schema: Schema): (input: unknown) => t.TypeOf<Schema> {
|
||||
return (input: unknown) => {
|
||||
const error = validate(schema, input);
|
||||
if (error) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
// 2. Validate config/overrides against *partial* config schema. This ensures valid properties have valid types.
|
||||
const partialConfigSchema = tDeepPartial(blueprint.configSchema);
|
||||
|
||||
if (options.config) {
|
||||
const partialConfigValidation = validate(partialConfigSchema, options.config);
|
||||
if (partialConfigValidation instanceof StrictValidationError) {
|
||||
throw strictValidationErrorToConfigValidationError(partialConfigValidation);
|
||||
}
|
||||
}
|
||||
|
||||
if (options.overrides) {
|
||||
for (const override of options.overrides) {
|
||||
// Validate criteria and extra criteria
|
||||
// FIXME: This is ugly
|
||||
for (const key of Object.keys(override)) {
|
||||
if (!validTopLevelOverrideKeys.includes(key)) {
|
||||
if (strict) {
|
||||
throw new ConfigValidationError(`Unknown override criterion '${key}'`);
|
||||
}
|
||||
|
||||
delete override[key];
|
||||
}
|
||||
}
|
||||
if (override.extra != null) {
|
||||
for (const extraCriterion of Object.keys(override.extra)) {
|
||||
if (!blueprint.customOverrideCriteriaFunctions?.[extraCriterion]) {
|
||||
if (strict) {
|
||||
throw new ConfigValidationError(`Unknown override extra criterion '${extraCriterion}'`);
|
||||
}
|
||||
|
||||
delete override.extra[extraCriterion];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Validate override config
|
||||
const partialOverrideConfigValidation = decodeAndValidateStrict(partialConfigSchema, override.config || {});
|
||||
if (partialOverrideConfigValidation instanceof StrictValidationError) {
|
||||
throw strictValidationErrorToConfigValidationError(partialOverrideConfigValidation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Run custom preprocessor, if any
|
||||
if (customPreprocessor) {
|
||||
options = await customPreprocessor(options);
|
||||
}
|
||||
|
||||
// 4. Merge with default options and validate/decode the entire config
|
||||
let decodedConfig = {};
|
||||
const decodedOverrides: Array<PluginOverrideCriteria<unknown> & { config: any }> = [];
|
||||
|
||||
if (options.config) {
|
||||
decodedConfig = blueprint.configSchema
|
||||
? decodeAndValidateStrict(blueprint.configSchema, options.config)
|
||||
: options.config;
|
||||
if (decodedConfig instanceof StrictValidationError) {
|
||||
throw strictValidationErrorToConfigValidationError(decodedConfig);
|
||||
}
|
||||
}
|
||||
|
||||
if (options.overrides) {
|
||||
for (const override of options.overrides) {
|
||||
const overrideConfigMergedWithBaseConfig = configUtils.mergeConfig(options.config || {}, override.config || {});
|
||||
const decodedOverrideConfig = blueprint.configSchema
|
||||
? decodeAndValidateStrict(blueprint.configSchema, overrideConfigMergedWithBaseConfig)
|
||||
: overrideConfigMergedWithBaseConfig;
|
||||
if (decodedOverrideConfig instanceof StrictValidationError) {
|
||||
throw strictValidationErrorToConfigValidationError(decodedOverrideConfig);
|
||||
}
|
||||
decodedOverrides.push({
|
||||
...override,
|
||||
config: deepKeyIntersect(decodedOverrideConfig, override.config || {}),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
config: decodedConfig,
|
||||
overrides: decodedOverrides,
|
||||
};
|
||||
return input as t.TypeOf<Schema>;
|
||||
};
|
||||
}
|
||||
|
||||
export async function sendSuccessMessage(
|
||||
pluginData: AnyPluginData<any>,
|
||||
channel: TextChannel,
|
||||
channel: TextBasedChannel,
|
||||
body: string,
|
||||
allowedMentions?: MessageMentionOptions,
|
||||
): Promise<Message | undefined> {
|
||||
const emoji = pluginData.fullConfig.success_emoji || undefined;
|
||||
const formattedBody = successMessage(body, emoji);
|
||||
const content: MessageOptions = allowedMentions
|
||||
const content: MessageCreateOptions = allowedMentions
|
||||
? { content: formattedBody, allowedMentions }
|
||||
: { content: formattedBody };
|
||||
|
||||
return channel
|
||||
.send({ ...content }) // Force line break
|
||||
.catch((err) => {
|
||||
const channelInfo = channel.guild ? `${channel.id} (${channel.guild.id})` : channel.id;
|
||||
const channelInfo = "guild" in channel ? `${channel.id} (${channel.guild.id})` : channel.id;
|
||||
logger.warn(`Failed to send success message to ${channelInfo}): ${err.code} ${err.message}`);
|
||||
return undefined;
|
||||
});
|
||||
|
@ -209,20 +128,20 @@ export async function sendSuccessMessage(
|
|||
|
||||
export async function sendErrorMessage(
|
||||
pluginData: AnyPluginData<any>,
|
||||
channel: TextChannel,
|
||||
channel: TextBasedChannel,
|
||||
body: string,
|
||||
allowedMentions?: MessageMentionOptions,
|
||||
): Promise<Message | undefined> {
|
||||
const emoji = pluginData.fullConfig.error_emoji || undefined;
|
||||
const formattedBody = errorMessage(body, emoji);
|
||||
const content: MessageOptions = allowedMentions
|
||||
const content: MessageCreateOptions = allowedMentions
|
||||
? { content: formattedBody, allowedMentions }
|
||||
: { content: formattedBody };
|
||||
|
||||
return channel
|
||||
.send({ ...content }) // Force line break
|
||||
.catch((err) => {
|
||||
const channelInfo = channel.guild ? `${channel.id} (${channel.guild.id})` : channel.id;
|
||||
const channelInfo = "guild" in channel ? `${channel.id} (${channel.guild.id})` : channel.id;
|
||||
logger.warn(`Failed to send error message to ${channelInfo}): ${err.code} ${err.message}`);
|
||||
return undefined;
|
||||
});
|
||||
|
@ -230,11 +149,13 @@ export async function sendErrorMessage(
|
|||
|
||||
export function getBaseUrl(pluginData: AnyPluginData<any>) {
|
||||
const knub = pluginData.getKnubInstance() as TZeppelinKnub;
|
||||
// @ts-expect-error
|
||||
return knub.getGlobalConfig().url;
|
||||
}
|
||||
|
||||
export function isOwner(pluginData: AnyPluginData<any>, userId: string) {
|
||||
const knub = pluginData.getKnubInstance() as TZeppelinKnub;
|
||||
// @ts-expect-error
|
||||
const owners = knub.getGlobalConfig()?.owners;
|
||||
if (!owners) {
|
||||
return false;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue