3
0
Fork 0
mirror of https://github.com/ZeppelinBot/Zeppelin.git synced 2025-05-25 02:25:01 +00:00

Merge branch 'master' into master

This commit is contained in:
Ruby 2022-04-22 15:58:40 +04:00 committed by GitHub
commit 04e91aa87a
14 changed files with 287 additions and 24 deletions

View file

@ -11,7 +11,8 @@
"metal0", "metal0",
"roflmaoqwerty", "roflmaoqwerty",
"usoka", "usoka",
"vcokltfre" "vcokltfre",
"Rstar284"
], ],
"message": "Thank you for contributing to Zeppelin! We require contributors to sign our Contributor License Agreement (CLA). To let us review and merge your code, please visit https://github.com/ZeppelinBot/CLA to sign the CLA!" "message": "Thank you for contributing to Zeppelin! We require contributors to sign our Contributor License Agreement (CLA). To let us review and merge your code, please visit https://github.com/ZeppelinBot/CLA to sign the CLA!"
} }

View file

@ -90,10 +90,15 @@ export class ApiLogins extends BaseRepository {
const [loginId, token] = apiKey.split("."); const [loginId, token] = apiKey.split(".");
if (!loginId || !token) return; if (!loginId || !token) return;
const updatedTime = moment().utc().add(LOGIN_EXPIRY_TIME, "ms");
const login = await this.apiLogins.createQueryBuilder().where("id = :id", { id: loginId }).getOne();
if (!login || moment.utc(login.expires_at).isSameOrAfter(updatedTime)) return;
await this.apiLogins.update( await this.apiLogins.update(
{ id: loginId }, { id: loginId },
{ {
expires_at: moment().utc().add(LOGIN_EXPIRY_TIME, "ms").format(DBDateFormat), expires_at: updatedTime.format(DBDateFormat),
}, },
); );
} }

View file

@ -25,7 +25,7 @@ export const BanAction = automodAction({
const reason = actionConfig.reason || "Kicked automatically"; const reason = actionConfig.reason || "Kicked automatically";
const duration = actionConfig.duration ? convertDelayStringToMS(actionConfig.duration)! : undefined; const duration = actionConfig.duration ? convertDelayStringToMS(actionConfig.duration)! : undefined;
const contactMethods = actionConfig.notify ? resolveActionContactMethods(pluginData, actionConfig) : undefined; const contactMethods = actionConfig.notify ? resolveActionContactMethods(pluginData, actionConfig) : undefined;
const deleteMessageDays = actionConfig.deleteMessageDays || undefined; const deleteMessageDays = actionConfig.deleteMessageDays ?? undefined;
const caseArgs: Partial<CaseArgs> = { const caseArgs: Partial<CaseArgs> = {
modId: pluginData.client.user!.id, modId: pluginData.client.user!.id,

View file

@ -72,7 +72,7 @@ export const MatchAttachmentTypeTrigger = automodTrigger<MatchResultType>()({
return ( return (
asSingleLine(` asSingleLine(`
Matched attachment type \`${Util.escapeInlineCode(matchResult.extra.matchedType)}\` Matched attachment type \`${Util.escapeInlineCode(matchResult.extra.matchedType)}\`
(${matchResult.extra.mode === "blacklist" ? "(blacklisted)" : "(not in whitelist)"}) (${matchResult.extra.mode === "blacklist" ? "blacklisted" : "not in whitelist"})
in message (\`${contexts[0].message!.id}\`) in ${prettyChannel}: in message (\`${contexts[0].message!.id}\`) in ${prettyChannel}:
`) + messageSummary(contexts[0].message!) `) + messageSummary(contexts[0].message!)
); );

View file

@ -1,3 +1,4 @@
import type { Snowflake } from "discord-api-types/globals";
import { GuildPluginData } from "knub"; import { GuildPluginData } from "knub";
import { logger } from "../../../logger"; import { logger } from "../../../logger";
import { resolveUser } from "../../../utils"; import { resolveUser } from "../../../utils";
@ -13,9 +14,11 @@ export async function createCase(pluginData: GuildPluginData<CasesPluginType>, a
const modName = mod.tag; const modName = mod.tag;
let ppName: string | null = null; let ppName: string | null = null;
let ppId: Snowflake | null = null;
if (args.ppId) { if (args.ppId) {
const pp = await resolveUser(pluginData.client, args.ppId); const pp = await resolveUser(pluginData.client, args.ppId);
ppName = pp.tag; ppName = pp.tag;
ppId = pp.id;
} }
if (args.auditLogId) { if (args.auditLogId) {
@ -28,20 +31,20 @@ export async function createCase(pluginData: GuildPluginData<CasesPluginType>, a
const createdCase = await pluginData.state.cases.create({ const createdCase = await pluginData.state.cases.create({
type: args.type, type: args.type,
user_id: args.userId, user_id: user.id,
user_name: userName, user_name: userName,
mod_id: args.modId, mod_id: mod.id,
mod_name: modName, mod_name: modName,
audit_log_id: args.auditLogId, audit_log_id: args.auditLogId,
pp_id: args.ppId, pp_id: ppId,
pp_name: ppName, pp_name: ppName,
is_hidden: Boolean(args.hide), is_hidden: Boolean(args.hide),
}); });
if (args.reason || (args.noteDetails && args.noteDetails.length)) { if (args.reason || args.noteDetails?.length) {
await createCaseNote(pluginData, { await createCaseNote(pluginData, {
caseId: createdCase.id, caseId: createdCase.id,
modId: args.modId, modId: mod.id,
body: args.reason || "", body: args.reason || "",
automatic: args.automatic, automatic: args.automatic,
postInCaseLogOverride: false, postInCaseLogOverride: false,
@ -53,7 +56,7 @@ export async function createCase(pluginData: GuildPluginData<CasesPluginType>, a
for (const extraNote of args.extraNotes) { for (const extraNote of args.extraNotes) {
await createCaseNote(pluginData, { await createCaseNote(pluginData, {
caseId: createdCase.id, caseId: createdCase.id,
modId: args.modId, modId: mod.id,
body: extraNote, body: extraNote,
automatic: args.automatic, automatic: args.automatic,
postInCaseLogOverride: false, postInCaseLogOverride: false,

View file

@ -85,7 +85,7 @@ export async function banUserId(
pluginData.state.serverLogs.ignoreLog(LogType.MEMBER_BAN, userId); pluginData.state.serverLogs.ignoreLog(LogType.MEMBER_BAN, userId);
ignoreEvent(pluginData, IgnoredEventType.Ban, userId); ignoreEvent(pluginData, IgnoredEventType.Ban, userId);
try { try {
const deleteMessageDays = Math.min(30, Math.max(0, banOptions.deleteMessageDays ?? 1)); const deleteMessageDays = Math.min(7, Math.max(0, banOptions.deleteMessageDays ?? 1));
await pluginData.guild.bans.create(userId as Snowflake, { await pluginData.guild.bans.create(userId as Snowflake, {
days: deleteMessageDays, days: deleteMessageDays,
reason: reason ?? undefined, reason: reason ?? undefined,

View file

@ -8,7 +8,7 @@ export const pluginInfo: ZeppelinGuildPluginBlueprint["info"] = {
`), `),
configurationGuide: trimPluginDescription(` configurationGuide: trimPluginDescription(`
### Getting started ### Getting started
To get started, request an API key for Phisherman following the instructions at https://docs.phisherman.gg/#/api/getting-started?id=requesting-api-access. To get started, request an API key for Phisherman following the instructions at https://docs.phisherman.gg/guide/getting-started.html#requesting-api-access
Then, add the api key to the plugin's config: Then, add the api key to the plugin's config:
~~~yml ~~~yml

View file

@ -7,8 +7,9 @@ import { GuildArchives } from "../../data/GuildArchives";
import { GuildLogs } from "../../data/GuildLogs"; import { GuildLogs } from "../../data/GuildLogs";
import { GuildSavedMessages } from "../../data/GuildSavedMessages"; import { GuildSavedMessages } from "../../data/GuildSavedMessages";
import { GuildTags } from "../../data/GuildTags"; import { GuildTags } from "../../data/GuildTags";
import { GuildTagAliases } from "src/data/GuildTagAliases";
import { mapToPublicFn } from "../../pluginUtils"; import { mapToPublicFn } from "../../pluginUtils";
import { convertDelayStringToMS } from "../../utils"; import { convertDelayStringToMS, trimPluginDescription } from "../../utils";
import { TimeAndDatePlugin } from "../TimeAndDate/TimeAndDatePlugin"; import { TimeAndDatePlugin } from "../TimeAndDate/TimeAndDatePlugin";
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint"; import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
import { TagCreateCmd } from "./commands/TagCreateCmd"; import { TagCreateCmd } from "./commands/TagCreateCmd";
@ -22,7 +23,8 @@ import { onMessageCreate } from "./util/onMessageCreate";
import { onMessageDelete } from "./util/onMessageDelete"; import { onMessageDelete } from "./util/onMessageDelete";
import { renderTagBody } from "./util/renderTagBody"; import { renderTagBody } from "./util/renderTagBody";
import { LogsPlugin } from "../Logs/LogsPlugin"; import { LogsPlugin } from "../Logs/LogsPlugin";
import { GuildTagAliases } from "src/data/GuildTagAliases"; import { generateTemplateMarkdown } from "./docs";
import { TemplateFunctions } from "./templateFunctions";
const defaultOptions: PluginOptions<TagsPluginType> = { const defaultOptions: PluginOptions<TagsPluginType> = {
config: { config: {
@ -59,6 +61,17 @@ export const TagsPlugin = zeppelinGuildPlugin<TagsPluginType>()({
showInDocs: true, showInDocs: true,
info: { info: {
prettyName: "Tags", prettyName: "Tags",
description: "Tags are a way to store and reuse information.",
configurationGuide: trimPluginDescription(`
### Template Functions
You can use template functions in your tags. These functions are called when the tag is rendered.
You can use these functions to render dynamic content, or to access information from the message and/or user calling the tag.
You use them by adding a \`{}\` on your tag.
Here are the functions you can use in your tags:
${generateTemplateMarkdown(TemplateFunctions)}
`),
}, },
configSchema: ConfigSchema, configSchema: ConfigSchema,

View file

@ -0,0 +1,17 @@
import { trimPluginDescription } from "src/utils";
import { TemplateFunction } from "./types";
export function generateTemplateMarkdown(definitions: TemplateFunction[]): string {
return definitions
.map(def => {
const usage = def.signature ?? `(${def.arguments.join(", ")})`;
const examples = def.examples?.map(ex => `> \`{${ex}}\``).join("\n") ?? null;
return trimPluginDescription(`
## ${def.name}
**${def.description}**\n
__Usage__: \`{${def.name}${usage}}\`\n
${examples ? `__Examples__:\n${examples}` : ""}\n\n
`);
})
.join("\n\n");
}

View file

@ -0,0 +1,166 @@
import { TemplateFunction } from "./types";
// TODO: Generate this dynamically, lmao
export const TemplateFunctions: TemplateFunction[] = [
{
name: "if",
description: "Checks if a condition is true or false and returns the corresponding ifTrue or ifFalse",
returnValue: "boolean",
arguments: ["condition", "ifTrue", "ifFalse"],
examples: ['if(user.bot, "User is a bot", "User is not a bot")'],
},
{
name: "and",
description: "Checks if all provided conditions are true",
returnValue: "boolean",
arguments: ["condition1", "condition2", "..."],
examples: ["and(user.bot, user.verified)"],
},
{
name: "or",
description: "Checks if atleast one of the provided conditions is true",
returnValue: "boolean",
arguments: ["condition1", "condition2", "..."],
examples: ["or(user.bot, user.verified)"],
},
{
name: "not",
description: "Checks if the provided condition is false",
returnValue: "boolean",
arguments: ["condition"],
examples: ["not(user.bot)"],
},
{
name: "concat",
description: "Concatenates several arguments into a string",
returnValue: "string",
arguments: ["argument1", "argument2", "..."],
examples: ['concat("Hello ", user.username, "!")'],
},
{
name: "concatArr",
description: "Joins a array with the provided separator",
returnValue: "string",
arguments: ["array", "separator"],
examples: ['concatArr(["Hello", "World"], " ")'],
},
{
name: "eq",
description: "Checks if all provided arguments are equal to each other",
returnValue: "boolean",
arguments: ["argument1", "argument2", "..."],
examples: ['eq(user.id, "106391128718245888")'],
},
{
name: "gt",
description: "Checks if the first argument is greater than the second",
returnValue: "boolean",
arguments: ["argument1", "argument2"],
examples: ["gt(5, 2)"],
},
{
name: "gte",
description: "Checks if the first argument is greater or equal to the second",
returnValue: "boolean",
arguments: ["argument1", "argument2"],
examples: ["gte(2, 2)"],
},
{
name: "lt",
description: "Checks if the first argument is smaller than the second",
returnValue: "boolean",
arguments: ["argument1", "argument2"],
examples: ["lt(2, 5)"],
},
{
name: "lte",
description: "Checks if the first argument is smaller or equal to the second",
returnValue: "boolean",
arguments: ["argument1", "argument2"],
examples: ["lte(2, 2)"],
},
{
name: "slice",
description: "Slices a string argument at start and end",
returnValue: "string",
arguments: ["string", "start", "end"],
examples: ['slice("Hello World", 0, 5)'],
},
{
name: "lower",
description: "Converts a string argument to lowercase",
returnValue: "string",
arguments: ["string"],
examples: ['lower("Hello World")'],
},
{
name: "upper",
description: "Converts a string argument to uppercase",
returnValue: "string",
arguments: ["string"],
examples: ['upper("Hello World")'],
},
{
name: "upperFirst",
description: "Converts the first character of a string argument to uppercase",
returnValue: "string",
arguments: ["string"],
examples: ['upperFirst("hello World")'],
},
{
name: "rand",
description: "Returns a random number between from and to, optionally using seed",
returnValue: "number",
arguments: ["from", "to", "seed"],
examples: ["rand(1, 10)"],
},
{
name: "round",
description: "Rounds a number to the given decimal places",
returnValue: "number",
arguments: ["number", "decimalPlaces"],
examples: ["round(1.2345, 2)"],
},
{
name: "add",
description: "Adds two or more numbers",
returnValue: "number",
arguments: ["number1", "number2", "..."],
examples: ["add(1, 2)"],
},
{
name: "sub",
description: "Subtracts two or more numbers",
returnValue: "number",
arguments: ["number1", "number2", "..."],
examples: ["sub(3, 1)"],
},
{
name: "mul",
description: "Multiplies two or more numbers",
returnValue: "number",
arguments: ["number1", "number2", "..."],
examples: ["mul(2, 3)"],
},
{
name: "div",
description: "Divides two or more numbers",
returnValue: "number",
arguments: ["number1", "number2", "..."],
examples: ["div(6, 2)"],
},
{
name: "cases",
description: "Returns the argument at position",
returnValue: "any",
arguments: ["position", "argument1", "argument2", "..."],
examples: ['cases(1, "Hello", "World")'],
},
{
name: "choose",
description: "Returns a random argument",
returnValue: "any",
arguments: ["argument1", "argument2", "..."],
examples: ['choose("Hello", "World", "!")'],
},
];

View file

@ -61,5 +61,14 @@ export interface TagsPluginType extends BasePluginType {
}; };
} }
export interface TemplateFunction {
name: string;
description: string;
arguments: string[];
returnValue: string;
signature?: string;
examples?: string[];
}
export const tagsCmd = typedGuildCommand<TagsPluginType>(); export const tagsCmd = typedGuildCommand<TagsPluginType>();
export const tagsEvt = typedGuildEventListener<TagsPluginType>(); export const tagsEvt = typedGuildEventListener<TagsPluginType>();

View file

@ -1,8 +1,9 @@
import { MessageEmbedOptions, Role } from "discord.js"; import { MessageEmbedOptions, Permissions, Role } from "discord.js";
import humanizeDuration from "humanize-duration"; import humanizeDuration from "humanize-duration";
import { GuildPluginData } from "knub"; import { GuildPluginData } from "knub";
import moment from "moment-timezone"; import moment from "moment-timezone";
import { EmbedWith, preEmbedPadding, trimLines } from "../../../utils"; import { EmbedWith, preEmbedPadding, trimLines } from "../../../utils";
import { PERMISSION_NAMES } from "../../../utils/permissionNames.js";
import { TimeAndDatePlugin } from "../../TimeAndDate/TimeAndDatePlugin"; import { TimeAndDatePlugin } from "../../TimeAndDate/TimeAndDatePlugin";
import { UtilityPluginType } from "../types"; import { UtilityPluginType } from "../types";
@ -35,14 +36,9 @@ export async function getRoleInfoEmbed(
round: true, round: true,
}); });
const rolePerms = Object.keys(role.permissions.toJSON()).map((p) => const rolePerms = role.permissions.has(Permissions.FLAGS.ADMINISTRATOR)
p ? [PERMISSION_NAMES.ADMINISTRATOR]
// Voice channel related permission names start with 'voice' : role.permissions.toArray().map((p) => PERMISSION_NAMES[p]);
.replace(/^voice/i, "")
.replace(/([a-z])([A-Z])/g, "$1 $2")
.toLowerCase()
.replace(/(^\w{1})|(\s{1}\w{1})/g, (l) => l.toUpperCase()),
);
// -1 because of the @everyone role // -1 because of the @everyone role
const totalGuildRoles = pluginData.guild.roles.cache.size - 1; const totalGuildRoles = pluginData.guild.roles.cache.size - 1;

View file

@ -16,6 +16,13 @@ import {
import { TimeAndDatePlugin } from "../../TimeAndDate/TimeAndDatePlugin"; import { TimeAndDatePlugin } from "../../TimeAndDate/TimeAndDatePlugin";
import { UtilityPluginType } from "../types"; import { UtilityPluginType } from "../types";
const MAX_ROLES_TO_DISPLAY = 15;
const trimRoles = (roles: string[]) =>
roles.length > MAX_ROLES_TO_DISPLAY
? roles.slice(0, MAX_ROLES_TO_DISPLAY).join(", ") + `, and ${MAX_ROLES_TO_DISPLAY - roles.length} more roles`
: roles.join(", ");
export async function getUserInfoEmbed( export async function getUserInfoEmbed(
pluginData: GuildPluginData<UtilityPluginType>, pluginData: GuildPluginData<UtilityPluginType>,
userId: string, userId: string,
@ -109,7 +116,7 @@ export async function getUserInfoEmbed(
name: preEmbedPadding + "Member information", name: preEmbedPadding + "Member information",
value: trimLines(` value: trimLines(`
${user.bot ? "Added" : "Joined"}: **${joinAge} ago** (\`${prettyJoinedAt}\`) ${user.bot ? "Added" : "Joined"}: **${joinAge} ago** (\`${prettyJoinedAt}\`)
${roles.length > 0 ? "Roles: " + roles.map((r) => `<@&${r.id}>`).join(", ") : ""} ${roles.length > 0 ? "Roles: " + trimRoles(roles.map((r) => `<@&${r.id}>`)) : ""}
`), `),
}); });

View file

@ -0,0 +1,46 @@
import { PermissionFlags } from "discord.js";
import { EMPTY_CHAR } from "../utils";
export const PERMISSION_NAMES: Record<keyof PermissionFlags, string> = {
ADD_REACTIONS: "Add Reactions",
ADMINISTRATOR: "Administrator",
ATTACH_FILES: "Attach Files",
BAN_MEMBERS: "Ban Members",
CHANGE_NICKNAME: "Change Nickname",
CONNECT: "Connect",
CREATE_INSTANT_INVITE: "Create Invite",
CREATE_PRIVATE_THREADS: "Create Private Threads",
CREATE_PUBLIC_THREADS: "Create Public Threads",
DEAFEN_MEMBERS: "Deafen Members",
EMBED_LINKS: "Embed Links",
KICK_MEMBERS: "Kick Members",
MANAGE_CHANNELS: "Manage Channels",
MANAGE_EMOJIS_AND_STICKERS: "Manage Emojis and Stickers",
MANAGE_GUILD: "Manage Server",
MANAGE_MESSAGES: "Manage Messages",
MANAGE_NICKNAMES: "Manage Nicknames",
MANAGE_ROLES: "Manage Roles",
MANAGE_THREADS: "Manage Threads",
MANAGE_WEBHOOKS: "Manage Webhooks",
MENTION_EVERYONE: `Mention @${EMPTY_CHAR}everyone, @${EMPTY_CHAR}here, and All Roles`,
MOVE_MEMBERS: "Move Members",
MUTE_MEMBERS: "Mute Members",
PRIORITY_SPEAKER: "Priority Speaker",
READ_MESSAGE_HISTORY: "Read Message History",
REQUEST_TO_SPEAK: "Request to Speak",
SEND_MESSAGES: "Send Messages",
SEND_MESSAGES_IN_THREADS: "Send Messages in Threads",
SEND_TTS_MESSAGES: "Send Text-To-Speech Messages",
SPEAK: "Speak",
START_EMBEDDED_ACTIVITIES: "Start Embedded Activities",
STREAM: "Video",
USE_APPLICATION_COMMANDS: "Use Application Commands",
USE_EXTERNAL_EMOJIS: "Use External Emoji",
USE_EXTERNAL_STICKERS: "Use External Stickers",
USE_PRIVATE_THREADS: "Use Private Threads",
USE_PUBLIC_THREADS: "Use Public Threads",
USE_VAD: "Use Voice Activity",
VIEW_AUDIT_LOG: "View Audit Log",
VIEW_CHANNEL: "View Channels",
VIEW_GUILD_INSIGHTS: "View Guild Insights",
};