-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(*): Discord.js v13 update (#353)
* feat(adminCommands): write interaction objects * feat(botCommands): write interaction objects * feat(mainCommands): write interaction objects * feat(settingsCommands): write interaction objects * feat(interactions): add index files * fix(interactions): remove setSettingCommand * chore(deps): update Discord.js and remove Commando * feat(interactions): add main index file * feat(EventHandlers): remove and update event handlers * feat(Client): break Commando out of Client and SettingProvider * feat(applicationConfig): remove redundant settings * feat(Client): update types * refactor(types): remove argument types * fix(*): change xID to xId * fix(*): overloads and timers * fix(Managers): rename add with _add * fix(Managers): update and improve resolve methods * fix(Managers): remove iterable constructor argument * feat(MessageCreateEventHandler): default to development env * feat(Commands): bind commands and factory in container * feat(Dispatcher): implement dispatcher * feat(bin): make update commands script * feat(*): use Client Ready generic argument where possible * feat(verificationService): move methods to own service * chore(deps): update Discord.js to v13.2.0 * feat(argumentTypes): readd RobloxUserArgumentType * feat(AroraClient): add Ready generic type parameter * feat(Channel * feat(commands): port first command And do some style fixes * refactor(commands): remove old ban commands * feat(Dispatcher): update parseArgs to use custom validate/parse * feat(arguments): port util and create argument class * feat(dispatcher): use default value when specified * feat(InteractionCreateEventHandler): reply to interaction with error * refactor: move guild extensions to own class * feat: add default-emoji argument type * feat: add date and time argument types * fix: use argument name in result when specified * refactor: improve whitespace checks * feat: implement GuildContextManager * refactor: remove Role and TextChannel extensions * refactor: pass context to structures and managers * refactor: remove unused managers * chore: formatting changes and fixes * feat(Commands): port training commands to new structure * refactor(Commands): port promote and demote commands * refactor(Commands): port exile commands * refactor(Commands): reformat and improve ported commands * refactor(Commands): port persistent role commands * refactor(Commands): port shout command * fix(Interactions): correctly filter choices * fix(bin): require reflect-metadata * refactor(Commands): port bot commands * refactor(Commands): port first few main commands * refactor(Commands): port last main commands * fix(RobloxUserArgumentType): verification data fetching * refactor(ArgumentTypes): make structure argument type * refactor: port groups commands and support sub command groups * refactor: fixes and make types stricter * refactor(ArgumentTypes): readd json-object and message argument types * refactor(BansCommand): use of new (min|max)_value constraints * fix(Interactions): change defaultPermission to default_permission * fix(ChannelLinksInteraction): make command option names lowercase * refactor(ArgumentTypes): add PanelArgumentType * feat: implement union argument types * refactor: some improvements * refactor(Commands): port panel commands * refactor(Commands): port channel links commands * refactor: move channel links and persistent roles methods to own service * fix: run yarn install * fix: lint errors after merge * fix: BaseCommandInteraction import * fix(Client): improve and fix types * fix: update commands * refactor: port settings commands and fix types * refactor: last settings commands * refactor: fix all lint and tsc errors * chore: update discord.js and api types and fix some type imports * fix: client passing into command constructor * refactor: improve constructor factory * refactor: use Inversify's interfaces.Newable instead of Constructor type * refactor: Dispatcher and SettingProvider client handling and utilise numeric separators * revert: move packetHandlerFactory back to Client * refactor: improve types and fix poll command * refactor: improve Client constructor and fix promise lints * refactor: remove redundant Promise.resolve * fix: remove double unref * refactor: reformat cron.schedule and setTimeout call * fix: styling * refactor: overwrite _add in BaseManager to reduce ts-expect-error directives * feat: add category-channel and text-channel argument types * fix: category-channel class name * refactor: rename GuildContextX with GuildX * fix: disallow overwriting id column on repository.save * fix(interactions): change id options to string type * feat(MessageCreateEventHandler): send message on successful deploy * fix(TagCommand): fix formatting * fix(Argument): correctly resolve union type * fix(BaseCommand): bind this argument on calling command function * refactor: move GuildSetting to constants * fix(argumentTypes): correctly escape digit symbol * refactor: move dependency injections to client To avoid circular dependencies returning undefined. Should come up with a better fix in the future. * refactor(managers): import GuildContext as type only where possible * fix(setActivityCommand): correctly transform ActivityTypes to choices * fix(GroupsCommand): use correct key name * fix(TagCommand): fix formatting when who is null * refactor(Client): improve failSilently method typings * chore(setActivityCommand): improve styling * fix(Ticket) lint error * feat(interactions): specify export types * fix(package): move discord-api-types to dependencies * feat: deploy commands in publish image workflow * fix(Client): use PartialTypes type instead of value * fix(settingsInteraction): make value option optional * fix(Argument): correctly check if valid before parsing * fix(SettingsCommand): enum check * refactor(*): fully utilize Inversify and remove inversify-inject-decorators (#410) * feat(argumentTypes): add boolean and integer type * chore: styling fixes * refactor(interactions): improve folder structure * fix: deploy commands in deploy job * refactor: improve imports * feat(argumentTypes): add custom-emoji argument type * feat(eventHandlers): log command runs * refactor(argumentTypes): don't parse when invalid * feat(GuildGroupManager): make factory types stricter * fix(package): change engine version constraint * refactor: move types to own util file * refactor: use ManagerFactory type where possible * refactor: use Inversify's factory types where possible * fix(container): commandFactory typings * chore(deps): update discord-api-types to v0.33.0 * feat: use discord api v10 * chore(deps): update discord.js to v13.7.0 * fix: cachetype errors * feat(Dispatcher): support attachment option type * feat(commands): disable all commands by default * feat: add database migration * fix: revert change in workflow * fix: actually use API v10 in updateCommands * feat: don't disable status command by default
- Loading branch information
Showing
285 changed files
with
7,614 additions
and
6,700 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
#!/usr/bin/env node | ||
'use strict' | ||
|
||
require('dotenv').config() | ||
|
||
const { REST } = require('@discordjs/rest') | ||
const { Routes } = require('discord-api-types/v10') | ||
const applicationCommands = require('../dist/interactions/data/application-commands') | ||
|
||
async function updateCommands () { | ||
const rest = new REST({ version: '10' }).setToken(process.env.DISCORD_TOKEN) | ||
const application = await rest.get(Routes.oauth2CurrentApplication()) | ||
await rest.put(Routes.applicationCommands(application.id), { body: Object.values(applicationCommands) }) | ||
} | ||
|
||
updateCommands() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -22,11 +22,11 @@ | |
"axios": "^0.26.0", | ||
"class-validator": "^0.13.2", | ||
"common-tags": "^1.8.2", | ||
"discord.js": "^12.5.3", | ||
"discord.js-commando": "^0.12.3", | ||
"discord-api-types": "^0.33.0", | ||
"discord.js": "^13.7.0", | ||
"dotenv": "^16.0.0", | ||
"emoji-regex": "^10.0.0", | ||
"inversify": "^6.0.1", | ||
"inversify-inject-decorators": "^3.1.0", | ||
"lodash": "^4.17.21", | ||
"node-cron": "^3.0.0", | ||
"pg": "^8.7.1", | ||
|
@@ -36,6 +36,7 @@ | |
"ws": "^8.3.0" | ||
}, | ||
"devDependencies": { | ||
"@discordjs/rest": "^0.3.0", | ||
"@guidojw/bloxy": "^5.7.6", | ||
"@types/common-tags": "^1.8.1", | ||
"@types/lodash": "^4.14.178", | ||
|
@@ -54,7 +55,7 @@ | |
"typescript": "^4.5.3" | ||
}, | ||
"engines": { | ||
"node": ">=14" | ||
"node": ">=16.6.0" | ||
}, | ||
"packageManager": "[email protected]" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import BaseArgumentType from './base' | ||
import { injectable } from 'inversify' | ||
|
||
@injectable() | ||
export default class AlwaysArgumentType extends BaseArgumentType<string> { | ||
public validate (): boolean { | ||
return true | ||
} | ||
|
||
public parse (value: string): string { | ||
return value | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
import type { Collection, CommandInteraction } from 'discord.js' | ||
import { type Constructor, constants } from '../utils' | ||
import type { DataManager, GuildContextManager } from '../managers' | ||
import type { GuildContext, IdentifiableStructure } from '../structures' | ||
import { inject, injectable, named, unmanaged } from 'inversify' | ||
import type { Argument } from '../interactions/application-commands' | ||
import type { IdentifiableEntity } from '../entities' | ||
import lodash from 'lodash' | ||
import pluralize from 'pluralize' | ||
|
||
const { TYPES } = constants | ||
|
||
@injectable() | ||
export default abstract class BaseArgumentType<T> { | ||
public abstract validate ( | ||
value: string, | ||
interaction: CommandInteraction, | ||
arg: Argument<T> | ||
): boolean | string | Promise<boolean | string> | ||
|
||
public abstract parse ( | ||
value: string, | ||
interaction: CommandInteraction, | ||
arg: Argument<T> | ||
): T | null | Promise<T | null> | ||
} | ||
|
||
export class BaseStructureArgumentType< | ||
T extends IdentifiableStructure<number, U>, | ||
U extends IdentifiableEntity | ||
> extends BaseArgumentType<T> { | ||
@inject(TYPES.Manager) | ||
@named('GuildContextManager') | ||
private readonly guildContexts!: GuildContextManager | ||
|
||
protected readonly holds: Constructor<T> | ||
|
||
private readonly managerName: string | ||
|
||
public constructor (@unmanaged() holds: Constructor<T>, @unmanaged() managerName?: string) { | ||
super() | ||
|
||
this.holds = holds | ||
this.managerName = typeof managerName === 'undefined' | ||
? pluralize(lodash.camelCase(holds.name)) | ||
: managerName | ||
} | ||
|
||
public validate ( | ||
value: string, | ||
interaction: CommandInteraction, | ||
_arg: Argument<T> | ||
): boolean | string | Promise<boolean | string> { | ||
if (!interaction.inGuild()) { | ||
return false | ||
} | ||
const context = this.guildContexts.resolve(interaction.guildId) as GuildContext | ||
|
||
const manager = context[this.managerName as keyof typeof context] as unknown as DataManager<number, T, unknown, U> | ||
const id = parseInt(value) | ||
if (!isNaN(id)) { | ||
const structure = manager.cache.get(id) | ||
return typeof structure !== 'undefined' && structure instanceof this.holds | ||
} | ||
const search = value.toLowerCase() | ||
const structures: Collection<number, T> = manager.cache.filter(this.filterInexact(search)) | ||
if (structures.size === 1) { | ||
return true | ||
} | ||
const exactStructures = structures.filter(this.filterExact(search)) | ||
return exactStructures.size === 1 | ||
} | ||
|
||
public parse ( | ||
value: string, | ||
interaction: CommandInteraction, | ||
_arg: Argument<T> | ||
): T | null | Promise<T | null> { | ||
if (!interaction.inGuild()) { | ||
return null | ||
} | ||
const context = this.guildContexts.resolve(interaction.guildId) as GuildContext | ||
|
||
const manager = context[this.managerName as keyof typeof context] as unknown as DataManager<number, T, unknown, U> | ||
const id = parseInt(value) | ||
if (!isNaN(id)) { | ||
return manager.cache.get(id) ?? null | ||
} | ||
const search = value.toLowerCase() | ||
const structures = manager.cache.filter(this.filterInexact(search)) | ||
if (structures.size === 0) { | ||
return null | ||
} | ||
if (structures.size === 1) { | ||
return structures.first() as T | ||
} | ||
const exactStructures = structures.filter(this.filterExact(search)) | ||
if (exactStructures.size === 1) { | ||
return exactStructures.first() as T | ||
} | ||
return null | ||
} | ||
|
||
protected filterExact (search: string): (structure: T) => boolean { | ||
return structure => structure instanceof this.holds && structure.toString().toLowerCase() === search | ||
} | ||
|
||
protected filterInexact (search: string): (structure: T) => boolean { | ||
return structure => structure instanceof this.holds && structure.toString().toLowerCase().includes(search) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import BaseArgumentType from './base' | ||
import { injectable } from 'inversify' | ||
|
||
@injectable() | ||
export default class BooleanArgumentType extends BaseArgumentType<boolean> { | ||
private readonly truthy = ['true', 't', 'yes', 'y', 'on', 'enable', 'enabled', '1', '+'] | ||
private readonly falsy = ['false', 'f', 'no', 'n', 'off', 'disable', 'disabled', '0', '-'] | ||
|
||
public validate (value: string): boolean { | ||
const search = value.toLowerCase() | ||
return this.truthy.includes(search) || this.falsy.includes(search) | ||
} | ||
|
||
public parse (value: string): boolean | null { | ||
if (!this.validate(value)) { | ||
return null | ||
} | ||
const search = value.toLowerCase() | ||
return this.truthy.includes(search) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import { CategoryChannel, type CommandInteraction } from 'discord.js' | ||
import BaseArgumentType from './base' | ||
import { injectable } from 'inversify' | ||
|
||
@injectable() | ||
export default class CategoryChannelArgumentType extends BaseArgumentType<CategoryChannel> { | ||
public validate (value: string, interaction: CommandInteraction): boolean { | ||
if (!interaction.inCachedGuild()) { | ||
return false | ||
} | ||
|
||
const match = value.match(/(\d+)/) | ||
if (match === null) { | ||
return false | ||
} | ||
const channel = interaction.guild.channels.resolve(match[0]) | ||
return channel !== null && channel instanceof CategoryChannel | ||
} | ||
|
||
public parse (value: string, interaction: CommandInteraction): CategoryChannel | null { | ||
if (!interaction.inCachedGuild()) { | ||
return null | ||
} | ||
|
||
const match = value.match(/(\d+)/) | ||
if (match === null) { | ||
return null | ||
} | ||
const channel = interaction.guild.channels.resolve(match[0]) | ||
return channel instanceof CategoryChannel ? channel : null | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import { BaseStructureArgumentType } from './base' | ||
import { ChannelGroup } from '../structures' | ||
import type { Group as GroupEntity } from '../entities' | ||
import { injectable } from 'inversify' | ||
|
||
@injectable() | ||
export default class ChannelGroupArgumentType extends BaseStructureArgumentType<ChannelGroup, GroupEntity> { | ||
public constructor () { | ||
super(ChannelGroup, 'groups') | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
import type { CommandInteraction, GuildEmoji } from 'discord.js' | ||
import BaseArgumentType from './base' | ||
import { injectable } from 'inversify' | ||
|
||
@injectable() | ||
export default class CustomEmojiArgumentType extends BaseArgumentType<GuildEmoji> { | ||
public validate (value: string, interaction: CommandInteraction): boolean { | ||
const match = value.match(/^(?:<a?:([a-zA-Z0-9_]+):)?([0-9]+)>?$/) | ||
if (match !== null && interaction.client.emojis.cache.has(match[2])) { | ||
return true | ||
} | ||
if (!interaction.inCachedGuild()) { | ||
return false | ||
} | ||
const search = value.toLowerCase() | ||
const emojis = interaction.guild.emojis.cache.filter(this.filterInexact(search)) | ||
if (emojis.size === 1) { | ||
return true | ||
} | ||
const exactEmojis = interaction.guild.emojis.cache.filter(this.filterExact(search)) | ||
return exactEmojis.size === 1 | ||
} | ||
|
||
public parse (value: string, interaction: CommandInteraction): GuildEmoji | null { | ||
const match = value.match(/^(?:<a?:([a-zA-Z0-9_]+):)?([0-9]+)>?$/) | ||
if (match !== null) { | ||
return interaction.client.emojis.cache.get(match[2]) ?? null | ||
} | ||
if (!interaction.inCachedGuild()) { | ||
return null | ||
} | ||
const search = value.toLowerCase() | ||
const emojis = interaction.guild.emojis.cache.filter(this.filterInexact(search)) | ||
if (emojis.size === 0) { | ||
return null | ||
} | ||
if (emojis.size === 1) { | ||
return emojis.first() as GuildEmoji | ||
} | ||
const exactEmojis = interaction.guild.emojis.cache.filter(this.filterExact(search)) | ||
if (exactEmojis.size === 1) { | ||
return exactEmojis.first() as GuildEmoji | ||
} | ||
return null | ||
} | ||
|
||
private filterExact (search: string): (structure: GuildEmoji) => boolean { | ||
return structure => structure.name?.toLowerCase() === search | ||
} | ||
|
||
private filterInexact (search: string): (structure: GuildEmoji) => boolean { | ||
return structure => structure.name?.toLowerCase().includes(search) ?? false | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import BaseArgumentType from './base' | ||
import { argumentUtil } from '../utils' | ||
import { injectable } from 'inversify' | ||
|
||
const { validDate } = argumentUtil | ||
|
||
@injectable() | ||
export default class DateArgumentType extends BaseArgumentType<string> { | ||
public validate (value: string): boolean { | ||
return validDate(value) | ||
} | ||
|
||
public parse (value: string): string | null { | ||
if (!this.validate(value)) { | ||
return null | ||
} | ||
return value | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import BaseArgumentType from './base' | ||
import emojiRegex from 'emoji-regex' | ||
import { injectable } from 'inversify' | ||
|
||
@injectable() | ||
export default class DefaultEmojiArgumentType extends BaseArgumentType<string> { | ||
public validate (value: string): boolean { | ||
return new RegExp(`^(?:${emojiRegex().source})$`).test(value) | ||
} | ||
|
||
public parse (value: string): string | null { | ||
if (!this.validate(value)) { | ||
return null | ||
} | ||
return value | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import { BaseStructureArgumentType } from './base' | ||
import { Group } from '../structures' | ||
import type { Group as GroupEntity } from '../entities' | ||
import { injectable } from 'inversify' | ||
|
||
@injectable() | ||
export default class GroupArgumentType extends BaseStructureArgumentType<Group, GroupEntity> { | ||
public constructor () { | ||
super(Group) | ||
} | ||
} |
Oops, something went wrong.