Various small changes/fixes
This commit is contained in:
parent
53705e76c5
commit
139630ce9f
|
@ -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(", ")}]\`.`);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -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}>`);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -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({
|
||||||
|
|
|
@ -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}`);
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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))
|
||||||
|
}
|
|
@ -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. */
|
||||||
|
|
Loading…
Reference in New Issue