Fix issues around embeds

This commit is contained in:
Dragory 2021-08-19 19:33:47 +03:00
parent dc53de8ae3
commit 81514276e9
No known key found for this signature in database
GPG key ID: 5F387BA66DF8AAC1
8 changed files with 111 additions and 21 deletions

View file

@ -13,6 +13,7 @@ import {
messageSummary,
renderRecursively,
resolveMember,
validateAndParseMessageContent,
verboseChannelMention,
verboseUserMention,
verboseUserName,
@ -134,10 +135,7 @@ export async function getLogMessage<TLogType extends keyof ILogTypeData>(
formatted = `\`[${timestamp}]\` ${formatted}`;
}
} else if (formatted != null) {
if (formatted.embed) {
formatted.embeds = [formatted.embed];
delete formatted.embed;
}
formatted = validateAndParseMessageContent(formatted);
if (formatted.embeds && Array.isArray(formatted.embeds) && includeEmbedTimestamp) {
for (const embed of formatted.embeds) {

View file

@ -82,6 +82,6 @@ export const PostEmbedCmd = postCmd({
);
}
actualPostCmd(pluginData, msg, args.channel, { embed }, args);
actualPostCmd(pluginData, msg, args.channel, { embeds: [embed] }, args);
},
});

View file

@ -22,8 +22,7 @@ export const ScheduledPostsListCmd = postCmd({
let i = 1;
const postLines = scheduledPosts.map(p => {
let previewText =
p.content.content || (p.content.embed && (p.content.embed.description || p.content.embed.title)) || "";
let previewText = p.content.content || p.content.embeds?.[0]?.description || p.content.embeds?.[0]?.title || "";
const isTruncated = previewText.length > SCHEDULED_POST_PREVIEW_TEXT_LENGTH;
@ -37,7 +36,7 @@ export const ScheduledPostsListCmd = postCmd({
.format(timeAndDate.getDateFormat("pretty_datetime"));
const parts = [`\`#${i++}\` \`[${prettyPostAt}]\` ${previewText}${isTruncated ? "..." : ""}`];
if (p.attachments.length) parts.push("*(with attachment)*");
if (p.content.embed) parts.push("*(embed)*");
if (p.content.embeds?.length) parts.push("*(embed)*");
if (p.repeat_until) {
parts.push(`*(repeated every ${humanizeDuration(p.repeat_interval)} until ${p.repeat_until})*`);
}

View file

@ -26,7 +26,7 @@ export const TagEvalCmd = tagsCmd({
{ member: msg.member },
);
if (!rendered.content && !rendered.embed) {
if (!rendered.content && !rendered.embeds?.length) {
sendErrorMessage(pluginData, msg.channel, "Evaluation resulted in an empty text");
return;
}

View file

@ -7,6 +7,7 @@ import { GuildTags } from "../../data/GuildTags";
import { tEmbed, tNullable } from "../../utils";
export const Tag = t.union([t.string, tEmbed]);
export type TTag = t.TypeOf<typeof Tag>;
export const TagCategory = t.type({
prefix: tNullable(t.string),

View file

@ -1,14 +1,13 @@
import * as t from "io-ts";
import { GuildPluginData } from "knub";
import { ExtendedMatchParams } from "knub/dist/config/PluginConfigManager";
import { renderTemplate, TemplateSafeValueContainer } from "../../../templateFormatter";
import { renderRecursively, StrictMessageContent } from "../../../utils";
import { Tag, TagsPluginType } from "../types";
import { TagsPluginType, TTag } from "../types";
import { findTagByName } from "./findTagByName";
export async function renderTagBody(
pluginData: GuildPluginData<TagsPluginType>,
body: t.TypeOf<typeof Tag>,
body: TTag,
args: unknown[] = [],
extraData = {},
subTagPermissionMatchParams?: ExtendedMatchParams,

View file

@ -1,13 +1,11 @@
import { GuildMember } from "discord.js";
import * as t from "io-ts";
import { GuildPluginData } from "knub";
import { parseArguments } from "knub-command-manager";
import { memberToTemplateSafeMember, userToTemplateSafeUser } from "../../../utils/templateSafeObjects";
import { LogType } from "../../../data/LogType";
import { TemplateParseError } from "../../../templateFormatter";
import { StrictMessageContent } from "../../../utils";
import { StrictMessageContent, validateAndParseMessageContent } from "../../../utils";
import { LogsPlugin } from "../../Logs/LogsPlugin";
import { Tag, TagsPluginType } from "../types";
import { TagsPluginType, TTag } from "../types";
import { renderTagBody } from "./renderTagBody";
export async function renderTagFromString(
@ -15,7 +13,7 @@ export async function renderTagFromString(
str: string,
prefix: string,
tagName: string,
tagBody: t.TypeOf<typeof Tag>,
tagBody: TTag,
member: GuildMember,
): Promise<StrictMessageContent | null> {
const variableStr = str.slice(prefix.length + tagName.length).trim();
@ -23,7 +21,7 @@ export async function renderTagFromString(
// Format the string
try {
return renderTagBody(
const rendered = await renderTagBody(
pluginData,
tagBody,
tagArgs,
@ -33,6 +31,8 @@ export async function renderTagFromString(
},
{ member },
);
return validateAndParseMessageContent(rendered);
} catch (e) {
if (e instanceof TemplateParseError) {
const logs = pluginData.getPlugin(LogsPlugin);

View file

@ -44,6 +44,7 @@ import { ChannelTypeStrings } from "./types";
import { sendDM } from "./utils/sendDM";
import { waitForButtonConfirm } from "./utils/waitForInteraction";
import { decodeAndValidateStrict, StrictValidationError } from "./validatorUtils";
import { z } from "zod";
const fsp = fs.promises;
@ -320,25 +321,117 @@ export const tEmbed = t.type({
),
});
export const zEmbedInput = z.object({
title: z.string().optional(),
description: z.string().optional(),
url: z.string().optional(),
timestamp: z.number().optional(),
color: z.number().optional(),
footer: z.optional(
z.object({
text: z.string(),
icon_url: z.string().optional(),
}),
),
image: z.optional(
z.object({
url: z.string().optional(),
width: z.number().optional(),
height: z.number().optional(),
}),
),
thumbnail: z.optional(
z.object({
url: z.string().optional(),
width: z.number().optional(),
height: z.number().optional(),
}),
),
video: z.optional(
z.object({
url: z.string().optional(),
width: z.number().optional(),
height: z.number().optional(),
}),
),
provider: z.optional(
z.object({
name: z.string(),
url: z.string().optional(),
}),
),
fields: z.optional(
z.array(
z.object({
name: z.string().optional(),
value: z.string().optional(),
inline: z.boolean().optional(),
}),
),
),
author: z
.optional(
z.object({
name: z.string(),
url: z.string().optional(),
width: z.number().optional(),
height: z.number().optional(),
}),
)
.nullable(),
});
export type EmbedWith<T extends keyof MessageEmbedOptions> = MessageEmbedOptions &
Pick<Required<MessageEmbedOptions>, T>;
export const zStrictMessageContent = z.object({
content: z.string().optional(),
tts: z.boolean().optional(),
embeds: z.array(zEmbedInput).optional(),
});
export type ZStrictMessageContent = z.infer<typeof zStrictMessageContent>;
export type StrictMessageContent = {
content?: string;
tts?: boolean;
disableEveryone?: boolean;
embed?: MessageEmbedOptions;
embeds?: MessageEmbedOptions[];
};
export const tStrictMessageContent = t.type({
content: tNullable(t.string),
tts: tNullable(t.boolean),
disableEveryone: tNullable(t.boolean),
embed: tNullable(tEmbed),
embeds: tNullable(t.array(tEmbed)),
});
export const tMessageContent = t.union([t.string, tStrictMessageContent]);
export function validateAndParseMessageContent(input: unknown): StrictMessageContent {
if (input == null) {
return {};
}
if (typeof input !== "object") {
return { content: String(input) };
}
// Migrate embed -> embeds
if ((input as any).embed) {
(input as any).embeds = [(input as any).embed];
delete (input as any).embed;
}
return (zStrictMessageContent.parse(input) as unknown) as StrictMessageContent;
}
/**
* Mirrors AllowedMentions from Eris
*/