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 {Config, Storage} from "../core/structures";
import {PermissionNames, getPermissionLevel} from "../core/permissions";
import {botHasPermission} from "../index";
import {Permissions} from "discord.js";
function getLogBuffer(type: string)
{
@ -11,12 +13,7 @@ function getLogBuffer(type: string)
}]};
}
const activities: { [type: string]: string } = {
playing: "",
listening: "",
streaming: "",
watching: ""
};
const activities = ["playing", "listening", "streaming", "watching"];
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.",
@ -63,7 +60,7 @@ export default new Command({
$.channel.send(getLogBuffer("info"));
},
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>
{
const type = $.args[0];
@ -71,7 +68,7 @@ export default new Command({
if(type in logs)
$.channel.send(getLogBuffer(type));
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,
async run($: CommonLibrary): Promise<any>
{
try {
const nickName = $.args.join(" ");
const trav = $.guild?.members.cache.find(member => member.id === $.client.user?.id);
await trav?.setNickname(nickName);
$.message.delete({timeout: 5000});
$.channel.send(`Nickname set to \`${nickName}\``)
.then(m => m.delete({timeout: 5000}));
} catch (e) {
console.log(e);
}
const nickName = $.args.join(" ");
const trav = $.guild?.members.cache.find(member => member.id === $.client.user?.id);
await trav?.setNickname(nickName);
if(botHasPermission($.guild, Permissions.FLAGS.MANAGE_MESSAGES))
$.message.delete({timeout: 5000}).catch($.handler.bind($));
$.channel.send(`Nickname set to \`${nickName}\``)
.then(m => m.delete({timeout: 5000}));
}
}),
guilds: new Command({
@ -152,17 +146,17 @@ export default new Command({
$.channel.send("Activity set to default.")
},
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>
{
const type = $.args[0];
if(type in activities) {
if(activities.includes(type)) {
$.client.user?.setActivity($.args.slice(1).join(" "), {type: $.args[0].toUpperCase()})
$.channel.send(`Set activity to \`${$.args[0].toUpperCase()}\` \`${$.args.slice(1).join(" ")}\`.`)
}
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>
{
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({
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:
{
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 $ from "./lib";
// Last Updated: Discord.js v12.2.0
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
interface EventOptions<K extends keyof ClientEvents>
{
readonly on?: Function;
readonly once?: Function;
readonly on?: (...args: ClientEvents[K]) => void;
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 once: Function|null;
private readonly on?: (...args: ClientEvents[K]) => void;
private readonly once?: (...args: ClientEvents[K]) => void;
constructor(options: EventOptions)
constructor(options: EventOptions<K>)
{
this.on = options.on || null;
this.once = options.once || null;
this.on = options.on;
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".
public attach(client: Client, event: string)
public attach(client: Client, event: K)
{
if(this.on)
client.on(event as any, this.on as any);
client.on(event, this.on);
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 event = (await import(`../events/${header}`)).default;
if(EVENTS.includes(header))
if((Object.values(Constants.Events) as string[]).includes(header))
{
event.attach(client, 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 FileManager from "./storage";
import {eventListeners} from "../events/messageReactionRemove";
import {client} from "../index";
import {botHasPermission} from "../index";
/** A type that describes what the library module does. */
export interface CommonLibrary
@ -170,10 +170,10 @@ $.paginate = async(message: Message, senderID: string, total: number, callback:
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.
// 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);
if(canDeleteEmotes && user.id !== client.user?.id)
if(canDeleteEmotes)
reaction.users.remove(user);
return false;
@ -258,7 +258,7 @@ export function parseArgs(line: string): string[]
* - `%%` = `%`
* - 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 inVariable = false;
@ -276,7 +276,7 @@ export function parseVars(line: string, definitions: {[key: string]: string}, in
{
if(token in definitions)
result += definitions[token];
else if(invalid === undefined || invalid === null)
else if(invalid === null)
result += `%${token}%`;
else
result += invalid;
@ -352,7 +352,7 @@ export interface GenericJSON
export abstract class GenericStructure
{
protected __meta__ = "generic";
private __meta__ = "generic";
constructor(tag?: string)
{

View File

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

View File

@ -1,15 +1,15 @@
import Event from "../core/event";
import Command, {loadCommands} from "../core/command";
import {hasPermission, getPermissionLevel, PermissionNames} from "../core/permissions";
import $ from "../core/lib";
import {Message, Permissions, Collection} from "discord.js";
import {Permissions, Collection} from "discord.js";
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.
let commands: Collection<string, Command>|null = null;
export default new Event({
async on(message: Message)
export default new Event<"message">({
async on(message)
{
// Load commands if it hasn't already done so. Luckily, it's called once at most.
if(!commands)

View File

@ -1,15 +1,15 @@
import Event from "../core/event";
import {MessageReaction, User, PartialUser, Permissions} from "discord.js";
import {client} from "../index";
import {Permissions} from "discord.js";
import {botHasPermission} from "../index";
// 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();
// Attached to the client, there can be one event listener attached to a message ID which is executed if present.
export default new Event({
on(reaction: MessageReaction, user: User|PartialUser)
export default new Event<"messageReactionRemove">({
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)
{

View File

@ -3,7 +3,7 @@ import {client} from "../index";
import $ from "../core/lib";
import {Config} from "../core/structures";
export default new Event({
export default new Event<"ready">({
once()
{
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 {Config} from "./core/structures";
import {loadCommands} from "./core/command";
@ -13,4 +13,9 @@ setup.init().then(() => {
loadCommands();
loadEvents(client);
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(" ") : [];
const support = (answers.support as string);
Config.support = support !== "" ? support.split(" ") : [];
Config.save();
Config.save(false);
}
},
/** Prompt the user to set their token again. */