mirror of
https://github.com/ZeppelinBot/Zeppelin.git
synced 2025-03-15 05:41:51 +00:00
templateFormatter: return empty string for null/undefined variables; Tags: catch template syntax errors on tag creation; add mention() tag function
This commit is contained in:
parent
db5d93b5c2
commit
f27da2c56f
2 changed files with 55 additions and 23 deletions
|
@ -1,4 +1,4 @@
|
|||
import { Plugin, decorators as d, IPluginOptions } from "knub";
|
||||
import { decorators as d, IPluginOptions } from "knub";
|
||||
import { Message, TextChannel } from "eris";
|
||||
import { errorMessage, successMessage } from "../utils";
|
||||
import { GuildTags } from "../data/GuildTags";
|
||||
|
@ -7,20 +7,9 @@ import { SavedMessage } from "../data/entities/SavedMessage";
|
|||
import moment from "moment-timezone";
|
||||
import humanizeDuration from "humanize-duration";
|
||||
import { ZeppelinPlugin } from "./ZeppelinPlugin";
|
||||
import { renderTemplate } from "../templateFormatter";
|
||||
import { escapeBacktickString } from "jest-snapshot/build/utils";
|
||||
import { parseTemplate, renderTemplate, TemplateParseError } from "../templateFormatter";
|
||||
import { GuildArchives } from "../data/GuildArchives";
|
||||
|
||||
const TAG_FUNCTIONS = {
|
||||
countdown(toDate) {
|
||||
const now = moment();
|
||||
const target = moment(toDate, "YYYY-MM-DD HH:mm:ss");
|
||||
const diff = target.diff(now);
|
||||
const result = humanizeDuration(diff, { largest: 2, round: true });
|
||||
return diff >= 0 ? result : `${result} ago`;
|
||||
},
|
||||
};
|
||||
|
||||
interface ITagsPluginConfig {
|
||||
prefix: string;
|
||||
delete_with_command: boolean;
|
||||
|
@ -42,6 +31,8 @@ export class TagsPlugin extends ZeppelinPlugin<ITagsPluginConfig, ITagsPluginPer
|
|||
private onMessageCreateFn;
|
||||
private onMessageDeleteFn;
|
||||
|
||||
protected tagFunctions;
|
||||
|
||||
getDefaultOptions(): IPluginOptions<ITagsPluginConfig, ITagsPluginPermissions> {
|
||||
return {
|
||||
config: {
|
||||
|
@ -77,6 +68,37 @@ export class TagsPlugin extends ZeppelinPlugin<ITagsPluginConfig, ITagsPluginPer
|
|||
|
||||
this.onMessageDeleteFn = this.onMessageDelete.bind(this);
|
||||
this.savedMessages.events.on("delete", this.onMessageDeleteFn);
|
||||
|
||||
this.tagFunctions = {
|
||||
countdown(toDate) {
|
||||
if (typeof toDate !== "string") return "";
|
||||
|
||||
const now = moment();
|
||||
const target = moment(toDate, "YYYY-MM-DD HH:mm:ss");
|
||||
if (!target.isValid()) return "";
|
||||
|
||||
const diff = target.diff(now);
|
||||
const result = humanizeDuration(diff, { largest: 2, round: true });
|
||||
return diff >= 0 ? result : `${result} ago`;
|
||||
},
|
||||
|
||||
mention: input => {
|
||||
if (typeof input !== "string") return "";
|
||||
if (input.match(/^<(@#)(!&)\d+>$/)) {
|
||||
return input;
|
||||
}
|
||||
|
||||
if (this.guild.members.has(input) || this.bot.users.has(input)) {
|
||||
return `<@!${input}>`;
|
||||
}
|
||||
|
||||
if (this.guild.channels.has(input) || this.bot.channelGuildMap[input]) {
|
||||
return `<#${input}>`;
|
||||
}
|
||||
|
||||
return input;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
onUnload() {
|
||||
|
@ -118,6 +140,17 @@ export class TagsPlugin extends ZeppelinPlugin<ITagsPluginConfig, ITagsPluginPer
|
|||
@d.command("tag", "<tag:string> <body:string$>")
|
||||
@d.permission("create")
|
||||
async tagCmd(msg: Message, args: { tag: string; body: string }) {
|
||||
try {
|
||||
parseTemplate(args.body);
|
||||
} catch (e) {
|
||||
if (e instanceof TemplateParseError) {
|
||||
msg.channel.createMessage(errorMessage(`Invalid tag syntax: ${e.message}`));
|
||||
return;
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
await this.tags.createOrUpdate(args.tag, args.body, msg.author.id);
|
||||
|
||||
const prefix = this.getConfig().prefix;
|
||||
|
@ -164,7 +197,7 @@ export class TagsPlugin extends ZeppelinPlugin<ITagsPluginConfig, ITagsPluginPer
|
|||
// Format the string
|
||||
body = await renderTemplate(body, {
|
||||
args: tagArgs,
|
||||
...TAG_FUNCTIONS,
|
||||
...this.tagFunctions,
|
||||
});
|
||||
|
||||
const channel = this.guild.channels.get(msg.channel_id) as TextChannel;
|
||||
|
|
|
@ -94,9 +94,7 @@ export function parseTemplate(str: string): ParsedTemplate {
|
|||
inVar = false;
|
||||
};
|
||||
|
||||
let i = -1;
|
||||
for (const char of chars) {
|
||||
i++;
|
||||
for (const [i, char] of chars.entries()) {
|
||||
if (inVar) {
|
||||
if (currentVar) {
|
||||
if (currentVar._state.inArg) {
|
||||
|
@ -130,7 +128,7 @@ export function parseTemplate(str: string): ParsedTemplate {
|
|||
} else if (char === '"') {
|
||||
// A double quote can start a string argument, but only if we haven't committed to some other type of argument already
|
||||
if (currentVar._state.currentArgType !== null) {
|
||||
throw new TemplateParseError(`Unexpected char: ${char} at ${i}`);
|
||||
throw new TemplateParseError(`Unexpected char ${char} at ${i}`);
|
||||
}
|
||||
|
||||
currentVar._state.currentArgType = "string";
|
||||
|
@ -138,7 +136,7 @@ export function parseTemplate(str: string): ParsedTemplate {
|
|||
} else if (char.match(/\d/)) {
|
||||
// A number can start a string argument, but only if we haven't committed to some other type of argument already
|
||||
if (currentVar._state.currentArgType !== null) {
|
||||
throw new TemplateParseError(`Unexpected char: ${char}`);
|
||||
throw new TemplateParseError(`Unexpected char ${char} at ${i}`);
|
||||
}
|
||||
|
||||
currentVar._state.currentArgType = "number";
|
||||
|
@ -153,7 +151,7 @@ export function parseTemplate(str: string): ParsedTemplate {
|
|||
currentVar._state.currentArg = newVar;
|
||||
currentVar = newVar;
|
||||
} else {
|
||||
throw new TemplateParseError(`Unexpected char: ${char}`);
|
||||
throw new TemplateParseError(`Unexpected char ${char} at ${i}`);
|
||||
}
|
||||
} else {
|
||||
if (char === "(") {
|
||||
|
@ -180,7 +178,7 @@ export function parseTemplate(str: string): ParsedTemplate {
|
|||
if (char === "}") {
|
||||
exitInjectedVar();
|
||||
} else {
|
||||
throw new TemplateParseError(`Unexpected char: ${char}`);
|
||||
throw new TemplateParseError(`Unexpected char ${char} at ${i}`);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -233,10 +231,11 @@ async function evaluateTemplateVariable(theVar: ITemplateVar, values) {
|
|||
}
|
||||
}
|
||||
|
||||
return value(...args);
|
||||
const result = await value(...args);
|
||||
return result == null ? "" : result;
|
||||
}
|
||||
|
||||
return value;
|
||||
return value == null ? "" : value;
|
||||
}
|
||||
|
||||
export async function renderParsedTemplate(parsedTemplate: ParsedTemplate, values: any) {
|
||||
|
|
Loading…
Add table
Reference in a new issue