3
0
Fork 0
mirror of https://github.com/ZeppelinBot/Zeppelin.git synced 2025-03-16 22:21:51 +00:00

Pre-plugin moves

This commit is contained in:
Dark 2021-05-31 21:12:24 +02:00
parent 9fc045cd38
commit 8f7a6510eb
No known key found for this signature in database
GPG key ID: 384C4B4F5B1E25A8
13 changed files with 62 additions and 52 deletions

View file

@ -1,4 +1,4 @@
import { Guild } from "eris"; import { Guild } from "discord.js";
export enum ERRORS { export enum ERRORS {
NO_MUTE_ROLE_IN_CONFIG = 1, NO_MUTE_ROLE_IN_CONFIG = 1,

View file

@ -3,7 +3,6 @@ import {
convertDelayStringToMS, convertDelayStringToMS,
disableCodeBlocks, disableCodeBlocks,
disableInlineCode, disableInlineCode,
isSnowflake,
isValidSnowflake, isValidSnowflake,
resolveMember, resolveMember,
resolveUser, resolveUser,
@ -11,13 +10,12 @@ import {
roleMentionRegex, roleMentionRegex,
UnknownUser, UnknownUser,
} from "./utils"; } from "./utils";
import { GuildChannel, Member, TextChannel, User } from "eris";
import { baseTypeConverters, baseCommandParameterTypeHelpers, CommandContext, TypeConversionError } from "knub"; import { baseTypeConverters, baseCommandParameterTypeHelpers, CommandContext, TypeConversionError } from "knub";
import { createTypeHelper } from "knub-command-manager"; import { createTypeHelper } from "knub-command-manager";
import { getChannelIdFromMessageId } from "./data/getChannelIdFromMessageId";
import { MessageTarget, resolveMessageTarget } from "./utils/resolveMessageTarget"; import { MessageTarget, resolveMessageTarget } from "./utils/resolveMessageTarget";
import { inputPatternToRegExp } from "./validatorUtils"; import { inputPatternToRegExp } from "./validatorUtils";
import { isValidTimezone } from "./utils/isValidTimezone"; import { isValidTimezone } from "./utils/isValidTimezone";
import { GuildChannel, GuildMember, User } from "discord.js";
export const commandTypes = { export const commandTypes = {
...baseTypeConverters, ...baseTypeConverters,
@ -112,7 +110,7 @@ export const commandTypeHelpers = {
delay: createTypeHelper<number>(commandTypes.delay), delay: createTypeHelper<number>(commandTypes.delay),
resolvedUser: createTypeHelper<Promise<User>>(commandTypes.resolvedUser), resolvedUser: createTypeHelper<Promise<User>>(commandTypes.resolvedUser),
resolvedUserLoose: createTypeHelper<Promise<User | UnknownUser>>(commandTypes.resolvedUserLoose), resolvedUserLoose: createTypeHelper<Promise<User | UnknownUser>>(commandTypes.resolvedUserLoose),
resolvedMember: createTypeHelper<Promise<Member>>(commandTypes.resolvedMember), resolvedMember: createTypeHelper<Promise<GuildMember>>(commandTypes.resolvedMember),
messageTarget: createTypeHelper<Promise<MessageTarget>>(commandTypes.messageTarget), messageTarget: createTypeHelper<Promise<MessageTarget>>(commandTypes.messageTarget),
anyId: createTypeHelper<Promise<string>>(commandTypes.anyId), anyId: createTypeHelper<Promise<string>>(commandTypes.anyId),
regex: createTypeHelper<RegExp>(commandTypes.regex), regex: createTypeHelper<RegExp>(commandTypes.regex),

View file

@ -4,8 +4,8 @@ import { getRepository, Repository } from "typeorm";
import { BaseGuildRepository } from "./BaseGuildRepository"; import { BaseGuildRepository } from "./BaseGuildRepository";
import { trimLines } from "../utils"; import { trimLines } from "../utils";
import { SavedMessage } from "./entities/SavedMessage"; import { SavedMessage } from "./entities/SavedMessage";
import { Guild } from "eris";
import { renderTemplate } from "../templateFormatter"; import { renderTemplate } from "../templateFormatter";
import { Guild } from "discord.js";
const DEFAULT_EXPIRY_DAYS = 30; const DEFAULT_EXPIRY_DAYS = 30;
@ -73,7 +73,7 @@ export class GuildArchives extends BaseGuildRepository {
protected async renderLinesFromSavedMessages(savedMessages: SavedMessage[], guild: Guild) { protected async renderLinesFromSavedMessages(savedMessages: SavedMessage[], guild: Guild) {
const msgLines: string[] = []; const msgLines: string[] = [];
for (const msg of savedMessages) { for (const msg of savedMessages) {
const channel = guild.channels.get(msg.channel_id); const channel = guild.channels.cache.get(msg.channel_id);
const user = { ...msg.data.author, id: msg.user_id }; const user = { ...msg.data.author, id: msg.user_id };
const line = await renderTemplate(MESSAGE_ARCHIVE_MESSAGE_FORMAT, { const line = await renderTemplate(MESSAGE_ARCHIVE_MESSAGE_FORMAT, {

View file

@ -2,11 +2,11 @@ import { getRepository, Repository } from "typeorm";
import { BaseGuildRepository } from "./BaseGuildRepository"; import { BaseGuildRepository } from "./BaseGuildRepository";
import { ISavedMessageData, SavedMessage } from "./entities/SavedMessage"; import { ISavedMessageData, SavedMessage } from "./entities/SavedMessage";
import { QueuedEventEmitter } from "../QueuedEventEmitter"; import { QueuedEventEmitter } from "../QueuedEventEmitter";
import { GuildChannel, Message, PossiblyUncachedTextableChannel } from "eris";
import moment from "moment-timezone"; import moment from "moment-timezone";
import { MINUTES, SECONDS } from "../utils"; import { MINUTES, SECONDS } from "../utils";
import { isAPI } from "../globals"; import { isAPI } from "../globals";
import { cleanupMessages } from "./cleanup/messages"; import { cleanupMessages } from "./cleanup/messages";
import { GuildChannel, Message } from "discord.js";
if (!isAPI()) { if (!isAPI()) {
const CLEANUP_INTERVAL = 5 * MINUTES; const CLEANUP_INTERVAL = 5 * MINUTES;
@ -34,19 +34,19 @@ export class GuildSavedMessages extends BaseGuildRepository {
this.toBePermanent = new Set(); this.toBePermanent = new Set();
} }
public msgToSavedMessageData(msg: Message<PossiblyUncachedTextableChannel>): ISavedMessageData { public msgToSavedMessageData(msg: Message): ISavedMessageData {
const data: ISavedMessageData = { const data: ISavedMessageData = {
author: { author: {
username: msg.author.username, username: msg.author.username,
discriminator: msg.author.discriminator, discriminator: msg.author.discriminator,
}, },
content: msg.content, content: msg.content,
timestamp: msg.timestamp, timestamp: msg.createdTimestamp,
}; };
if (msg.attachments.length) data.attachments = msg.attachments; if (msg.attachments.size) data.attachments = msg.attachments.array();
if (msg.embeds.length) data.embeds = msg.embeds; if (msg.embeds.length) data.embeds = msg.embeds;
if (msg.stickers?.length) data.stickers = msg.stickers; if (msg.stickers?.size) data.stickers = msg.stickers.array();
return data; return data;
} }
@ -139,12 +139,12 @@ export class GuildSavedMessages extends BaseGuildRepository {
this.events.emit(`create:${data.id}`, [inserted]); this.events.emit(`create:${data.id}`, [inserted]);
} }
async createFromMsg(msg: Message<PossiblyUncachedTextableChannel>, overrides = {}) { async createFromMsg(msg: Message, overrides = {}) {
const existingSavedMsg = await this.find(msg.id); const existingSavedMsg = await this.find(msg.id);
if (existingSavedMsg) return; if (existingSavedMsg) return;
const savedMessageData = this.msgToSavedMessageData(msg); const savedMessageData = this.msgToSavedMessageData(msg);
const postedAt = moment.utc(msg.timestamp, "x").format("YYYY-MM-DD HH:mm:ss"); const postedAt = moment.utc(msg.createdTimestamp, "x").format("YYYY-MM-DD HH:mm:ss");
const data = { const data = {
id: msg.id, id: msg.id,
@ -222,7 +222,7 @@ export class GuildSavedMessages extends BaseGuildRepository {
this.events.emit(`update:${id}`, [newMessage, oldMessage]); this.events.emit(`update:${id}`, [newMessage, oldMessage]);
} }
async saveEditFromMsg(msg: Message<PossiblyUncachedTextableChannel>) { async saveEditFromMsg(msg: Message) {
const newData = this.msgToSavedMessageData(msg); const newData = this.msgToSavedMessageData(msg);
return this.saveEdit(msg.id, newData); return this.saveEdit(msg.id, newData);
} }

View file

@ -1,9 +1,9 @@
import { MessageAttachment, Sticker } from "discord.js";
import { Column, Entity, PrimaryColumn } from "typeorm"; import { Column, Entity, PrimaryColumn } from "typeorm";
import { createEncryptedJsonTransformer } from "../encryptedJsonTransformer"; import { createEncryptedJsonTransformer } from "../encryptedJsonTransformer";
import { Attachment, Sticker } from "eris";
export interface ISavedMessageData { export interface ISavedMessageData {
attachments?: Attachment[]; attachments?: MessageAttachment[];
author: { author: {
username: string; username: string;
discriminator: string; discriminator: string;

View file

@ -1,5 +1,5 @@
import { MessageAttachment } from "discord.js";
import { Column, Entity, PrimaryColumn } from "typeorm"; import { Column, Entity, PrimaryColumn } from "typeorm";
import { Attachment } from "eris";
import { StrictMessageContent } from "../../utils"; import { StrictMessageContent } from "../../utils";
@Entity("scheduled_posts") @Entity("scheduled_posts")
@ -18,7 +18,7 @@ export class ScheduledPost {
@Column("simple-json") content: StrictMessageContent; @Column("simple-json") content: StrictMessageContent;
@Column("simple-json") attachments: Attachment[]; @Column("simple-json") attachments: MessageAttachment[];
@Column({ type: String, nullable: true }) post_at: string | null; @Column({ type: String, nullable: true }) post_at: string | null;

View file

@ -2,7 +2,6 @@
* @file Utility functions that are plugin-instance-specific (i.e. use PluginData) * @file Utility functions that are plugin-instance-specific (i.e. use PluginData)
*/ */
import { AdvancedMessageContent, AllowedMentions, GuildTextableChannel, Member, Message, TextableChannel } from "eris";
import { CommandContext, configUtils, ConfigValidationError, GuildPluginData, helpers, PluginOptions } from "knub"; import { CommandContext, configUtils, ConfigValidationError, GuildPluginData, helpers, PluginOptions } from "knub";
import { decodeAndValidateStrict, StrictValidationError, validate } from "./validatorUtils"; import { decodeAndValidateStrict, StrictValidationError, validate } from "./validatorUtils";
import { deepKeyIntersect, errorMessage, successMessage, tDeepPartial, tNullable } from "./utils"; import { deepKeyIntersect, errorMessage, successMessage, tDeepPartial, tNullable } from "./utils";
@ -14,11 +13,17 @@ import { Tail } from "./utils/typeUtils";
import { AnyPluginData } from "knub/dist/plugins/PluginData"; import { AnyPluginData } from "knub/dist/plugins/PluginData";
import { ZeppelinPlugin } from "./plugins/ZeppelinPlugin"; import { ZeppelinPlugin } from "./plugins/ZeppelinPlugin";
import { logger } from "./logger"; import { logger } from "./logger";
import { APIMessage, GuildMember, Message, MessageMentionOptions, MessageOptions, TextChannel, User } from "discord.js";
const { getMemberLevel } = helpers; const { getMemberLevel } = helpers;
export function canActOn(pluginData: GuildPluginData<any>, member1: Member, member2: Member, allowSameLevel = false) { export function canActOn(
if (member2.id === pluginData.client.user.id) { pluginData: GuildPluginData<any>,
member1: GuildMember,
member2: GuildMember,
allowSameLevel = false,
) {
if (member2.id === pluginData.client.user!.id) {
return false; return false;
} }
@ -180,21 +185,19 @@ export function getPluginConfigPreprocessor(
export function sendSuccessMessage( export function sendSuccessMessage(
pluginData: AnyPluginData<any>, pluginData: AnyPluginData<any>,
channel: TextableChannel, channel: TextChannel,
body: string, body: string,
allowedMentions?: AllowedMentions, allowedMentions?: MessageMentionOptions,
): Promise<Message | undefined> { ): Promise<Message | undefined> {
const emoji = pluginData.fullConfig.success_emoji || undefined; const emoji = pluginData.fullConfig.success_emoji || undefined;
const formattedBody = successMessage(body, emoji); const formattedBody = successMessage(body, emoji);
const content: AdvancedMessageContent = allowedMentions const content: MessageOptions = allowedMentions
? { content: formattedBody, allowedMentions } ? { content: formattedBody, allowedMentions }
: { content: formattedBody }; : { content: formattedBody };
return channel return channel
.createMessage(content) // Force line break .send({ content }) // Force line break
.catch(err => { .catch(err => {
const channelInfo = (channel as GuildTextableChannel).guild const channelInfo = channel.guild ? `${channel.id} (${channel.guild.id})` : `${channel.id}`;
? `${channel.id} (${(channel as GuildTextableChannel).guild.id})`
: `${channel.id}`;
logger.warn(`Failed to send success message to ${channelInfo}): ${err.code} ${err.message}`); logger.warn(`Failed to send success message to ${channelInfo}): ${err.code} ${err.message}`);
return undefined; return undefined;
}); });
@ -202,21 +205,19 @@ export function sendSuccessMessage(
export function sendErrorMessage( export function sendErrorMessage(
pluginData: AnyPluginData<any>, pluginData: AnyPluginData<any>,
channel: TextableChannel, channel: TextChannel,
body: string, body: string,
allowedMentions?: AllowedMentions, allowedMentions?: MessageMentionOptions,
): Promise<Message | undefined> { ): Promise<Message | undefined> {
const emoji = pluginData.fullConfig.error_emoji || undefined; const emoji = pluginData.fullConfig.error_emoji || undefined;
const formattedBody = errorMessage(body, emoji); const formattedBody = errorMessage(body, emoji);
const content: AdvancedMessageContent = allowedMentions const content: MessageOptions = allowedMentions
? { content: formattedBody, allowedMentions } ? { content: formattedBody, allowedMentions }
: { content: formattedBody }; : { content: formattedBody };
return channel return channel
.createMessage(content) // Force line break .send({ ...content, split: false }) // Force line break
.catch(err => { .catch(err => {
const channelInfo = (channel as GuildTextableChannel).guild const channelInfo = channel.guild ? `${channel.id} (${channel.guild.id})` : `${channel.id}`;
? `${channel.id} (${(channel as GuildTextableChannel).guild.id})`
: `${channel.id}`;
logger.warn(`Failed to send error message to ${channelInfo}): ${err.code} ${err.message}`); logger.warn(`Failed to send error message to ${channelInfo}): ${err.code} ${err.message}`);
return undefined; return undefined;
}); });

View file

@ -1,6 +1,5 @@
import { BaseConfig, Knub } from "knub"; import { BaseConfig, Knub } from "knub";
import * as t from "io-ts"; import * as t from "io-ts";
import { Message } from "eris";
export interface ZeppelinGuildConfig extends BaseConfig<any> { export interface ZeppelinGuildConfig extends BaseConfig<any> {
success_emoji?: string; success_emoji?: string;

View file

@ -1,9 +1,9 @@
import { Constants, Guild, Member, Role } from "eris"; import { Guild, GuildMember, Permissions, Role } from "discord.js";
import { getMissingPermissions } from "./getMissingPermissions"; import { getMissingPermissions } from "./getMissingPermissions";
import { hasDiscordPermissions } from "./hasDiscordPermissions"; import { hasDiscordPermissions } from "./hasDiscordPermissions";
export function canAssignRole(guild: Guild, member: Member, roleId: string) { export function canAssignRole(guild: Guild, member: GuildMember, roleId: string) {
if (getMissingPermissions(member.permission, Constants.Permissions.manageRoles)) { if (getMissingPermissions(member.permissions, Permissions.FLAGS.MANAGE_ROLES)) {
return false; return false;
} }
@ -11,14 +11,14 @@ export function canAssignRole(guild: Guild, member: Member, roleId: string) {
return false; return false;
} }
const targetRole = guild.roles.get(roleId); const targetRole = guild.roles.cache.get(roleId);
if (!targetRole) { if (!targetRole) {
return false; return false;
} }
const memberRoles = member.roles.map(_roleId => guild.roles.get(_roleId)!); const memberRoles = member.roles.cache;
const highestRoleWithManageRoles = memberRoles.reduce<Role | null>((highest, role) => { const highestRoleWithManageRoles = memberRoles.reduce<Role | null>((highest, role) => {
if (!hasDiscordPermissions(role.permissions, Constants.Permissions.manageRoles)) return highest; if (!hasDiscordPermissions(role.permissions, Permissions.FLAGS.MANAGE_ROLES)) return highest;
if (highest == null) return role; if (highest == null) return role;
if (role.position > highest.position) return role; if (role.position > highest.position) return role;
return highest; return highest;

View file

@ -1,8 +1,8 @@
import { Constants, GuildChannel, Member } from "eris";
import { readChannelPermissions } from "./readChannelPermissions"; import { readChannelPermissions } from "./readChannelPermissions";
import { getMissingChannelPermissions } from "./getMissingChannelPermissions"; import { getMissingChannelPermissions } from "./getMissingChannelPermissions";
import { GuildChannel, GuildMember } from "discord.js";
export function canReadChannel(channel: GuildChannel, member: Member) { export function canReadChannel(channel: GuildChannel, member: GuildMember) {
// Not missing permissions required to read the channel = can read channel // Not missing permissions required to read the channel = can read channel
return !getMissingChannelPermissions(member, channel, readChannelPermissions); return !getMissingChannelPermissions(member, channel, readChannelPermissions);
} }

View file

@ -1,9 +1,18 @@
import { APIMessage, Client, Message, MessageReaction, PartialUser, TextChannel, User } from "discord.js"; import {
APIMessage,
Client,
Message,
MessageOptions,
MessageReaction,
PartialUser,
TextChannel,
User,
} from "discord.js";
import { Awaitable } from "knub/dist/utils"; import { Awaitable } from "knub/dist/utils";
import { MINUTES, noop } from "../utils"; import { MINUTES, noop } from "../utils";
import Timeout = NodeJS.Timeout; import Timeout = NodeJS.Timeout;
export type LoadPageFn = (page: number) => Awaitable<MessageContent>; export type LoadPageFn = (page: number) => Awaitable<MessageOptions>;
export interface PaginateMessageOpts { export interface PaginateMessageOpts {
timeout: number; timeout: number;
@ -24,7 +33,7 @@ export async function createPaginatedMessage(
): Promise<Message> { ): Promise<Message> {
const fullOpts = { ...defaultOpts, ...opts } as PaginateMessageOpts; const fullOpts = { ...defaultOpts, ...opts } as PaginateMessageOpts;
const firstPageContent = await loadPageFn(1); const firstPageContent = await loadPageFn(1);
const message = await channel.send(firstPageContent); const message = await channel.send({ content: firstPageContent });
let page = 1; let page = 1;
let pageLoadId = 0; // Used to avoid race conditions when rapidly switching pages let pageLoadId = 0; // Used to avoid race conditions when rapidly switching pages

View file

@ -1,11 +1,14 @@
import { PermissionOverwrites, Permissions } from "discord.js"; import { Permissions } from "discord.js";
/** /**
* @param resolvedPermissions A Permission object from e.g. GuildChannel#permissionsOf() or Member#permission * @param resolvedPermissions A Permission object from e.g. GuildChannel#permissionsOf() or Member#permission
* @param requiredPermissions Bitmask of required permissions * @param requiredPermissions Bitmask of required permissions
*/ */
export function hasDiscordPermissions(resolvedPermissions: PermissionOverwrites, requiredPermissions: number | bigint) { export function hasDiscordPermissions(
const allowedPermissions = BigInt(resolvedPermissions.allow); resolvedPermissions: Permissions | Readonly<Permissions>,
requiredPermissions: number | bigint,
) {
const allowedPermissions = BigInt(resolvedPermissions);
const nRequiredPermissions = BigInt(requiredPermissions); const nRequiredPermissions = BigInt(requiredPermissions);
if (Boolean(allowedPermissions & BigInt(Permissions.FLAGS.ADMINISTRATOR))) { if (Boolean(allowedPermissions & BigInt(Permissions.FLAGS.ADMINISTRATOR))) {

View file

@ -1,4 +1,4 @@
import { APIMessage, MessageOptions } from "discord.js"; import { MessageOptions } from "discord.js";
function embedHasContent(embed: any) { function embedHasContent(embed: any) {
for (const [key, value] of Object.entries(embed)) { for (const [key, value] of Object.entries(embed)) {