Various small changes/fixes

This commit is contained in:
WatDuhHekBro 2020-08-14 07:50:24 -05:00
parent 53705e76c5
commit 139630ce9f
11 changed files with 57 additions and 74 deletions

View File

@ -2,6 +2,8 @@ import Command from "../core/command";
import {CommonLibrary, logs} from "../core/lib"; import {CommonLibrary, logs} from "../core/lib";
import {Config, Storage} from "../core/structures"; import {Config, Storage} from "../core/structures";
import {PermissionNames, getPermissionLevel} from "../core/permissions"; import {PermissionNames, getPermissionLevel} from "../core/permissions";
import {botHasPermission} from "../index";
import {Permissions} from "discord.js";
function getLogBuffer(type: string) function getLogBuffer(type: string)
{ {
@ -11,12 +13,7 @@ function getLogBuffer(type: string)
}]}; }]};
} }
const activities: { [type: string]: string } = { const activities = ["playing", "listening", "streaming", "watching"];
playing: "",
listening: "",
streaming: "",
watching: ""
};
export default new Command({ export default new Command({
description: "An all-in-one command to do admin stuff. You need to be either an admin of the server or one of the bot's mechanics to use this command.", description: "An all-in-one command to do admin stuff. You need to be either an admin of the server or one of the bot's mechanics to use this command.",
@ -63,7 +60,7 @@ export default new Command({
$.channel.send(getLogBuffer("info")); $.channel.send(getLogBuffer("info"));
}, },
any: new Command({ any: new Command({
description: `Select a verbosity to listen to. Available levels: \`[${Object.keys(logs)}]\``, description: `Select a verbosity to listen to. Available levels: \`[${Object.keys(logs).join(", ")}]\``,
async run($: CommonLibrary): Promise<any> async run($: CommonLibrary): Promise<any>
{ {
const type = $.args[0]; const type = $.args[0];
@ -71,7 +68,7 @@ export default new Command({
if(type in logs) if(type in logs)
$.channel.send(getLogBuffer(type)); $.channel.send(getLogBuffer(type));
else else
$.channel.send(`Couldn't find a verbosity level named \`${type}\`! The available types are \`[${Object.keys(logs)}]\`.`); $.channel.send(`Couldn't find a verbosity level named \`${type}\`! The available types are \`[${Object.keys(logs).join(", ")}]\`.`);
} }
}) })
}), }),
@ -118,16 +115,13 @@ export default new Command({
permission: Command.PERMISSIONS.BOT_SUPPORT, permission: Command.PERMISSIONS.BOT_SUPPORT,
async run($: CommonLibrary): Promise<any> async run($: CommonLibrary): Promise<any>
{ {
try { const nickName = $.args.join(" ");
const nickName = $.args.join(" "); const trav = $.guild?.members.cache.find(member => member.id === $.client.user?.id);
const trav = $.guild?.members.cache.find(member => member.id === $.client.user?.id); await trav?.setNickname(nickName);
await trav?.setNickname(nickName); if(botHasPermission($.guild, Permissions.FLAGS.MANAGE_MESSAGES))
$.message.delete({timeout: 5000}); $.message.delete({timeout: 5000}).catch($.handler.bind($));
$.channel.send(`Nickname set to \`${nickName}\``) $.channel.send(`Nickname set to \`${nickName}\``)
.then(m => m.delete({timeout: 5000})); .then(m => m.delete({timeout: 5000}));
} catch (e) {
console.log(e);
}
} }
}), }),
guilds: new Command({ guilds: new Command({
@ -152,17 +146,17 @@ export default new Command({
$.channel.send("Activity set to default.") $.channel.send("Activity set to default.")
}, },
any: new Command({ any: new Command({
description: `Select an activity type to set. Available levels: \`[${Object.keys(activities)}]\``, description: `Select an activity type to set. Available levels: \`[${activities.join(", ")}]\``,
async run($: CommonLibrary): Promise<any> async run($: CommonLibrary): Promise<any>
{ {
const type = $.args[0]; const type = $.args[0];
if(type in activities) { if(activities.includes(type)) {
$.client.user?.setActivity($.args.slice(1).join(" "), {type: $.args[0].toUpperCase()}) $.client.user?.setActivity($.args.slice(1).join(" "), {type: $.args[0].toUpperCase()})
$.channel.send(`Set activity to \`${$.args[0].toUpperCase()}\` \`${$.args.slice(1).join(" ")}\`.`) $.channel.send(`Set activity to \`${$.args[0].toUpperCase()}\` \`${$.args.slice(1).join(" ")}\`.`)
} }
else else
$.channel.send(`Couldn't find an activity type named \`${type}\`! The available types are \`[${Object.keys(activities)}]\`.`); $.channel.send(`Couldn't find an activity type named \`${type}\`! The available types are \`[${activities.join(", ")}]\`.`);
} }
}) })
}) })

View File

@ -41,7 +41,7 @@ export default new Command({
async run($: CommonLibrary): Promise<any> async run($: CommonLibrary): Promise<any>
{ {
const sender = $.message.author; const sender = $.message.author;
$.channel.send(responses[Math.floor(Math.random() * responses.length)] + ` <@${sender.id}>`); $.channel.send($(responses).random() + ` <@${sender.id}>`);
} }
}) })
}), }),

View File

@ -6,7 +6,7 @@ import { verificationLevels, filterLevels, regions, flags } from "../defs/info";
export default new Command({ export default new Command({
description: "Command to provide all sorts of info about the current server, a user, etc.", description: "Command to provide all sorts of info about the current server, a user, etc.",
run: "Please provide an argument.\nFor help, run `.help info`.", run: "Please provide an argument.\nFor help, run `%prefix%help info`.",
subcommands: subcommands:
{ {
avatar: new Command({ avatar: new Command({

View File

@ -1,34 +1,31 @@
import {Client} from "discord.js"; import {Client, ClientEvents, Constants} from "discord.js";
import Storage from "./storage"; import Storage from "./storage";
import $ from "./lib"; import $ from "./lib";
// Last Updated: Discord.js v12.2.0 interface EventOptions<K extends keyof ClientEvents>
const EVENTS = ["channelCreate", "channelDelete", "channelPinsUpdate", "channelUpdate", "debug", "warn", "disconnect", "emojiCreate", "emojiDelete", "emojiUpdate", "error", "guildBanAdd", "guildBanRemove", "guildCreate", "guildDelete", "guildUnavailable", "guildIntegrationsUpdate", "guildMemberAdd", "guildMemberAvailable", "guildMemberRemove", "guildMembersChunk", "guildMemberSpeaking", "guildMemberUpdate", "guildUpdate", "inviteCreate", "inviteDelete", "message", "messageDelete", "messageReactionRemoveAll", "messageReactionRemoveEmoji", "messageDeleteBulk", "messageReactionAdd", "messageReactionRemove", "messageUpdate", "presenceUpdate", "rateLimit", "ready", "invalidated", "roleCreate", "roleDelete", "roleUpdate", "typingStart", "userUpdate", "voiceStateUpdate", "webhookUpdate", "shardDisconnect", "shardError", "shardReady", "shardReconnecting", "shardResume"];
interface EventOptions
{ {
readonly on?: Function; readonly on?: (...args: ClientEvents[K]) => void;
readonly once?: Function; readonly once?: (...args: ClientEvents[K]) => void;
} }
export default class Event export default class Event<K extends keyof ClientEvents>
{ {
private readonly on: Function|null; private readonly on?: (...args: ClientEvents[K]) => void;
private readonly once: Function|null; private readonly once?: (...args: ClientEvents[K]) => void;
constructor(options: EventOptions) constructor(options: EventOptions<K>)
{ {
this.on = options.on || null; this.on = options.on;
this.once = options.once || null; this.once = options.once;
} }
// For this function, I'm going to assume that the event is used with the correct arguments and that the event tag is checked in "storage.ts". // For this function, I'm going to assume that the event is used with the correct arguments and that the event tag is checked in "storage.ts".
public attach(client: Client, event: string) public attach(client: Client, event: K)
{ {
if(this.on) if(this.on)
client.on(event as any, this.on as any); client.on(event, this.on);
if(this.once) if(this.once)
client.once(event as any, this.once as any); client.once(event, this.once);
} }
} }
@ -39,7 +36,7 @@ export async function loadEvents(client: Client)
const header = file.substring(0, file.indexOf(".js")); const header = file.substring(0, file.indexOf(".js"));
const event = (await import(`../events/${header}`)).default; const event = (await import(`../events/${header}`)).default;
if(EVENTS.includes(header)) if((Object.values(Constants.Events) as string[]).includes(header))
{ {
event.attach(client, header); event.attach(client, header);
$.log(`Loading Event: ${header}`); $.log(`Loading Event: ${header}`);

View File

@ -3,7 +3,7 @@ import {Client, Message, TextChannel, DMChannel, NewsChannel, Guild, User, Guild
import chalk from "chalk"; import chalk from "chalk";
import FileManager from "./storage"; import FileManager from "./storage";
import {eventListeners} from "../events/messageReactionRemove"; import {eventListeners} from "../events/messageReactionRemove";
import {client} from "../index"; import {botHasPermission} from "../index";
/** A type that describes what the library module does. */ /** A type that describes what the library module does. */
export interface CommonLibrary export interface CommonLibrary
@ -170,10 +170,10 @@ $.paginate = async(message: Message, senderID: string, total: number, callback:
await message.awaitReactions((reaction, user) => { await message.awaitReactions((reaction, user) => {
// The reason this is inside the call is because it's possible to switch a user's permissions halfway and suddenly throw an error. // The reason this is inside the call is because it's possible to switch a user's permissions halfway and suddenly throw an error.
// This will dynamically adjust for that, switching modes depending on whether it currently has the "Manage Messages" permission. // This will dynamically adjust for that, switching modes depending on whether it currently has the "Manage Messages" permission.
const canDeleteEmotes = !!(client.user && message.guild?.members.resolve(client.user)?.hasPermission(Permissions.FLAGS.MANAGE_MESSAGES)); const canDeleteEmotes = botHasPermission(message.guild, Permissions.FLAGS.MANAGE_MESSAGES);
handle(reaction.emoji.name, user.id); handle(reaction.emoji.name, user.id);
if(canDeleteEmotes && user.id !== client.user?.id) if(canDeleteEmotes)
reaction.users.remove(user); reaction.users.remove(user);
return false; return false;
@ -258,7 +258,7 @@ export function parseArgs(line: string): string[]
* - `%%` = `%` * - `%%` = `%`
* - If the invalid token is null/undefined, nothing is changed. * - If the invalid token is null/undefined, nothing is changed.
*/ */
export function parseVars(line: string, definitions: {[key: string]: string}, invalid: string|null|undefined = ""): string export function parseVars(line: string, definitions: {[key: string]: string}, invalid: string|null = ""): string
{ {
let result = ""; let result = "";
let inVariable = false; let inVariable = false;
@ -276,7 +276,7 @@ export function parseVars(line: string, definitions: {[key: string]: string}, in
{ {
if(token in definitions) if(token in definitions)
result += definitions[token]; result += definitions[token];
else if(invalid === undefined || invalid === null) else if(invalid === null)
result += `%${token}%`; result += `%${token}%`;
else else
result += invalid; result += invalid;
@ -352,7 +352,7 @@ export interface GenericJSON
export abstract class GenericStructure export abstract class GenericStructure
{ {
protected __meta__ = "generic"; private __meta__ = "generic";
constructor(tag?: string) constructor(tag?: string)
{ {

View File

@ -38,30 +38,17 @@ const length = Object.keys(PERMISSIONS).length / 2;
export function hasPermission(member: GuildMember, permission: PERMISSIONS): boolean export function hasPermission(member: GuildMember, permission: PERMISSIONS): boolean
{ {
if(permission === PERMISSIONS.NONE)
return true;
for(let i = length-1; i >= permission; i--) for(let i = length-1; i >= permission; i--)
{ if(PermissionChecker[i](member))
const condition = PermissionChecker[i](member);
if(condition)
return true; return true;
}
return false; return false;
} }
export function getPermissionLevel(member: GuildMember): number export function getPermissionLevel(member: GuildMember): number
{ {
for(let i = length-1; i >= 0; i--) for(let i = length-1; i >= 0; i--)
{ if(PermissionChecker[i](member))
const condition = PermissionChecker[i](member);
if(condition)
return i; return i;
}
return 0; return 0;
} }

View File

@ -1,15 +1,15 @@
import Event from "../core/event"; import Event from "../core/event";
import Command, {loadCommands} from "../core/command"; import Command, {loadCommands} from "../core/command";
import {hasPermission, getPermissionLevel, PermissionNames} from "../core/permissions"; import {hasPermission, getPermissionLevel, PermissionNames} from "../core/permissions";
import $ from "../core/lib"; import {Permissions, Collection} from "discord.js";
import {Message, Permissions, Collection} from "discord.js";
import {getPrefix} from "../core/structures"; import {getPrefix} from "../core/structures";
import $ from "../core/lib";
// It's a rather hacky solution, but since there's no top-level await, I just have to make the loading conditional. // It's a rather hacky solution, but since there's no top-level await, I just have to make the loading conditional.
let commands: Collection<string, Command>|null = null; let commands: Collection<string, Command>|null = null;
export default new Event({ export default new Event<"message">({
async on(message: Message) async on(message)
{ {
// Load commands if it hasn't already done so. Luckily, it's called once at most. // Load commands if it hasn't already done so. Luckily, it's called once at most.
if(!commands) if(!commands)

View File

@ -1,15 +1,15 @@
import Event from "../core/event"; import Event from "../core/event";
import {MessageReaction, User, PartialUser, Permissions} from "discord.js"; import {Permissions} from "discord.js";
import {client} from "../index"; import {botHasPermission} from "../index";
// A list of message ID and callback pairs. You get the emote name and ID of the user reacting. // A list of message ID and callback pairs. You get the emote name and ID of the user reacting.
export const eventListeners: Map<string, (emote: string, id: string) => void> = new Map(); export const eventListeners: Map<string, (emote: string, id: string) => void> = new Map();
// Attached to the client, there can be one event listener attached to a message ID which is executed if present. // Attached to the client, there can be one event listener attached to a message ID which is executed if present.
export default new Event({ export default new Event<"messageReactionRemove">({
on(reaction: MessageReaction, user: User|PartialUser) on(reaction, user)
{ {
const canDeleteEmotes = !!(client.user && reaction.message.guild?.members.resolve(client.user)?.hasPermission(Permissions.FLAGS.MANAGE_MESSAGES)); const canDeleteEmotes = botHasPermission(reaction.message.guild, Permissions.FLAGS.MANAGE_MESSAGES);
if(!canDeleteEmotes) if(!canDeleteEmotes)
{ {

View File

@ -3,7 +3,7 @@ import {client} from "../index";
import $ from "../core/lib"; import $ from "../core/lib";
import {Config} from "../core/structures"; import {Config} from "../core/structures";
export default new Event({ export default new Event<"ready">({
once() once()
{ {
if(client.user) if(client.user)

View File

@ -1,4 +1,4 @@
import {Client} from "discord.js"; import {Client, Guild} from "discord.js";
import setup from "./setup"; import setup from "./setup";
import {Config} from "./core/structures"; import {Config} from "./core/structures";
import {loadCommands} from "./core/command"; import {loadCommands} from "./core/command";
@ -13,4 +13,9 @@ setup.init().then(() => {
loadCommands(); loadCommands();
loadEvents(client); loadEvents(client);
client.login(Config.token).catch(setup.again); client.login(Config.token).catch(setup.again);
}); });
export function botHasPermission(guild: Guild|null, permission: number): boolean
{
return !!(client.user && guild?.members.resolve(client.user)?.hasPermission(permission))
}

View File

@ -44,7 +44,7 @@ export default {
Config.admins = admins !== "" ? admins.split(" ") : []; Config.admins = admins !== "" ? admins.split(" ") : [];
const support = (answers.support as string); const support = (answers.support as string);
Config.support = support !== "" ? support.split(" ") : []; Config.support = support !== "" ? support.split(" ") : [];
Config.save(); Config.save(false);
} }
}, },
/** Prompt the user to set their token again. */ /** Prompt the user to set their token again. */